Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 65e47516 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes from topic "bionic_fdsan"

* changes:
  crasher: add close(fileno(FILE*)) and close(dirfd(DIR*)).
  debuggerd_handler: use syscall(__NR_close) instead of close.
  base: add support for tagged fd closure to unique_fd.
parents 881be58f 3fa9637e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -135,6 +135,7 @@ cc_test {
        "strings_test.cpp",
        "test_main.cpp",
        "test_utils_test.cpp",
        "unique_fd_test.cpp",
    ],
    target: {
        android: {
+75 −17
Original line number Diff line number Diff line
@@ -42,10 +42,29 @@
//
// unique_fd is also known as ScopedFd/ScopedFD/scoped_fd; mentioned here to help
// you find this class if you're searching for one of those names.

#if defined(__BIONIC__)
#include <android/fdsan.h>
#endif

namespace android {
namespace base {

struct DefaultCloser {
#if defined(__BIONIC__)
  static void Tag(int fd, void* old_addr, void* new_addr) {
    uint64_t old_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
                                                      reinterpret_cast<uint64_t>(old_addr));
    uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
                                                      reinterpret_cast<uint64_t>(new_addr));
    android_fdsan_exchange_owner_tag(fd, old_tag, new_tag);
  }
  static void Close(int fd, void* addr) {
    uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
                                                  reinterpret_cast<uint64_t>(addr));
    android_fdsan_close_with_tag(fd, tag);
  }
#else
  static void Close(int fd) {
    // Even if close(2) fails with EINTR, the fd will have been closed.
    // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
@@ -53,40 +72,75 @@ struct DefaultCloser {
    // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
    ::close(fd);
  }
#endif
};

template <typename Closer>
class unique_fd_impl final {
 public:
  unique_fd_impl() : value_(-1) {}
  unique_fd_impl() {}

  explicit unique_fd_impl(int value) : value_(value) {}
  explicit unique_fd_impl(int fd) { reset(fd); }
  ~unique_fd_impl() { reset(); }

  unique_fd_impl(unique_fd_impl&& other) : value_(other.release()) {}
  unique_fd_impl(unique_fd_impl&& other) { reset(other.release()); }
  unique_fd_impl& operator=(unique_fd_impl&& s) {
    reset(s.release());
    int fd = s.fd_;
    s.fd_ = -1;
    reset(fd, &s);
    return *this;
  }

  void reset(int new_value = -1) {
    if (value_ != -1) {
      Closer::Close(value_);
    }
    value_ = new_value;
  }
  void reset(int new_value = -1) { reset(new_value, nullptr); }

  int get() const { return value_; }
  int get() const { return fd_; }
  operator int() const { return get(); }

  int release() __attribute__((warn_unused_result)) {
    int ret = value_;
    value_ = -1;
    tag(fd_, this, nullptr);
    int ret = fd_;
    fd_ = -1;
    return ret;
  }

 private:
  int value_;
  void reset(int new_value, void* previous_tag) {
    if (fd_ != -1) {
      close(fd_, this);
    }

    fd_ = new_value;
    if (new_value != -1) {
      tag(new_value, previous_tag, this);
    }
  }

  int fd_ = -1;

  // Template magic to use Closer::Tag if available, and do nothing if not.
  // If Closer::Tag exists, this implementation is preferred, because int is a better match.
  // If not, this implementation is SFINAEd away, and the no-op below is the only one that exists.
  template <typename T = Closer>
  static auto tag(int fd, void* old_tag, void* new_tag)
      -> decltype(T::Tag(fd, old_tag, new_tag), void()) {
    T::Tag(fd, old_tag, new_tag);
  }

  template <typename T = Closer>
  static void tag(long, void*, void*) {
    // No-op.
  }

  // Same as above, to select between Closer::Close(int) and Closer::Close(int, void*).
  template <typename T = Closer>
  static auto close(int fd, void* tag_value) -> decltype(T::Close(fd, tag_value), void()) {
    T::Close(fd, tag_value);
  }

  template <typename T = Closer>
  static auto close(int fd, void*) -> decltype(T::Close(fd), void()) {
    T::Close(fd);
  }

  unique_fd_impl(const unique_fd_impl&);
  void operator=(const unique_fd_impl&);
@@ -97,7 +151,8 @@ using unique_fd = unique_fd_impl<DefaultCloser>;
#if !defined(_WIN32)

// Inline functions, so that they can be used header-only.
inline bool Pipe(unique_fd* read, unique_fd* write) {
template <typename Closer>
inline bool Pipe(unique_fd_impl<Closer>* read, unique_fd_impl<Closer>* write) {
  int pipefd[2];

#if defined(__linux__)
@@ -121,7 +176,9 @@ inline bool Pipe(unique_fd* read, unique_fd* write) {
  return true;
}

inline bool Socketpair(int domain, int type, int protocol, unique_fd* left, unique_fd* right) {
template <typename Closer>
inline bool Socketpair(int domain, int type, int protocol, unique_fd_impl<Closer>* left,
                       unique_fd_impl<Closer>* right) {
  int sockfd[2];
  if (socketpair(domain, type, protocol, sockfd) != 0) {
    return false;
@@ -131,7 +188,8 @@ inline bool Socketpair(int domain, int type, int protocol, unique_fd* left, uniq
  return true;
}

inline bool Socketpair(int type, unique_fd* left, unique_fd* right) {
template <typename Closer>
inline bool Socketpair(int type, unique_fd_impl<Closer>* left, unique_fd_impl<Closer>* right) {
  return Socketpair(AF_UNIX, type, 0, left, right);
}

+54 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "android-base/unique_fd.h"

#include <gtest/gtest.h>

#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

using android::base::unique_fd;

TEST(unique_fd, unowned_close) {
#if defined(__BIONIC__)
  unique_fd fd(open("/dev/null", O_RDONLY));
  EXPECT_DEATH(close(fd.get()), "incorrect tag");
#endif
}

TEST(unique_fd, untag_on_release) {
  unique_fd fd(open("/dev/null", O_RDONLY));
  close(fd.release());
}

TEST(unique_fd, move) {
  unique_fd fd(open("/dev/null", O_RDONLY));
  unique_fd fd_moved = std::move(fd);
  ASSERT_EQ(-1, fd.get());
  ASSERT_GT(fd_moved.get(), -1);
}

TEST(unique_fd, unowned_close_after_move) {
#if defined(__BIONIC__)
  unique_fd fd(open("/dev/null", O_RDONLY));
  unique_fd fd_moved = std::move(fd);
  ASSERT_EQ(-1, fd.get());
  ASSERT_GT(fd_moved.get(), -1);
  EXPECT_DEATH(close(fd_moved.get()), "incorrect tag");
#endif
}
+40 −32
Original line number Diff line number Diff line
@@ -183,6 +183,8 @@ static int usage() {
    fprintf(stderr, "  exit                  call exit(1)\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "  fortify               fail a _FORTIFY_SOURCE check\n");
    fprintf(stderr, "  fdsan_file            close a file descriptor that's owned by a FILE*\n");
    fprintf(stderr, "  fdsan_dir             close a file descriptor that's owned by a DIR*\n");
    fprintf(stderr, "  seccomp               fail a seccomp check\n");
#if defined(__arm__)
    fprintf(stderr, "  kuser_helper_version  call kuser_helper_version\n");
@@ -260,6 +262,12 @@ noinline int do_action(const char* arg) {
      char buf[10];
      __read_chk(-1, buf, 32, 10);
      while (true) pause();
    } else if (!strcasecmp(arg, "fdsan_file")) {
      FILE* f = fopen("/dev/null", "r");
      close(fileno(f));
    } else if (!strcasecmp(arg, "fdsan_dir")) {
      DIR* d = opendir("/dev/");
      close(dirfd(d));
    } else if (!strcasecmp(arg, "LOG(FATAL)")) {
      LOG(FATAL) << "hello " << 123;
    } else if (!strcasecmp(arg, "LOG_ALWAYS_FATAL")) {
@@ -295,8 +303,8 @@ noinline int do_action(const char* arg) {
    } else if (!strcasecmp(arg, "leak")) {
      leak();
    } else if (!strcasecmp(arg, "SIGSEGV-unmapped")) {
        char* map = reinterpret_cast<char*>(mmap(nullptr, sizeof(int), PROT_READ | PROT_WRITE,
                                                 MAP_SHARED | MAP_ANONYMOUS, -1, 0));
      char* map = reinterpret_cast<char*>(
          mmap(nullptr, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));
      munmap(map, sizeof(int));
      map[0] = '8';
    } else if (!strcasecmp(arg, "seccomp")) {
+12 −2
Original line number Diff line number Diff line
@@ -59,7 +59,16 @@
#include "protocol.h"

using android::base::Pipe;
using android::base::unique_fd;

// We muck with our fds in a 'thread' that doesn't share the same fd table.
// Close fds in that thread with a raw close syscall instead of going through libc.
struct FdsanBypassCloser {
  static void Close(int fd) {
    syscall(__NR_close, fd);
  }
};

using unique_fd = android::base::unique_fd_impl<FdsanBypassCloser>;

// see man(2) prctl, specifically the section about PR_GET_NAME
#define MAX_TASK_NAME_LEN (16)
@@ -299,7 +308,8 @@ static int debuggerd_dispatch_pseudothread(void* arg) {
  debugger_thread_info* thread_info = static_cast<debugger_thread_info*>(arg);

  for (int i = 0; i < 1024; ++i) {
    close(i);
    // Don't use close to avoid bionic's file descriptor ownership checks.
    syscall(__NR_close, i);
  }

  int devnull = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));