diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-02-02 23:49:00 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-02-02 23:49:00 +0000 |
commit | a01eb2b9dabaa67fd77dae8bf9d4ca9615b2ebf3 (patch) | |
tree | 158f5f4eba68adeaa20d94d9626b0ff92114be9e | |
parent | f640923cab48fdada0ac9135c4e36f2673281c17 (diff) | |
parent | ab5b3bd919db1c43d70e10b0adf042db0e7b017a (diff) | |
download | libbrillo-simpleperf-release.tar.gz |
Snap for 11400057 from ab5b3bd919db1c43d70e10b0adf042db0e7b017a to simpleperf-releasesimpleperf-release
Change-Id: I89e5860461548dcfed2ccc0196b65a3fc4c4bb9b
-rw-r--r-- | Android.bp | 4 | ||||
-rw-r--r-- | brillo/process.cc | 231 | ||||
-rw-r--r-- | brillo/process.h | 5 | ||||
-rw-r--r-- | brillo/secure_allocator.h | 11 | ||||
-rw-r--r-- | brillo/secure_blob_test.cc | 3 |
5 files changed, 141 insertions, 113 deletions
@@ -171,7 +171,9 @@ cc_library { static_libs: [ "libmodpb64", ], - header_libs: ["libgtest_prod_headers"], + header_libs: [ + "libgtest_prod_headers", + ], cflags: libbrillo_CFLAGS, export_include_dirs: ["."], diff --git a/brillo/process.cc b/brillo/process.cc index 54e91f0..1fb33bf 100644 --- a/brillo/process.cc +++ b/brillo/process.cc @@ -4,9 +4,14 @@ #include "brillo/process.h" +#ifdef __BIONIC__ +#include <android/fdsan.h> +#endif + #include <fcntl.h> #include <signal.h> #include <stdint.h> +#include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> @@ -18,7 +23,6 @@ #include <base/files/file_path.h> #include <base/files/file_util.h> #include <base/logging.h> -#include <base/memory/ptr_util.h> #include <base/posix/eintr_wrapper.h> #include <base/posix/file_descriptor_shuffle.h> #include <base/process/process_metrics.h> @@ -37,11 +41,9 @@ bool ReturnTrue() { return true; } -Process::Process() { -} +Process::Process() {} -Process::~Process() { -} +Process::~Process() {} bool Process::ProcessExists(pid_t pid) { return base::DirectoryExists( @@ -55,8 +57,7 @@ ProcessImpl::ProcessImpl() pre_exec_(base::Bind(&ReturnTrue)), search_path_(false), inherit_parent_signal_mask_(false), - close_unused_file_descriptors_(false) { -} + close_unused_file_descriptors_(false) {} ProcessImpl::~ProcessImpl() { Reset(0); @@ -117,7 +118,7 @@ void ProcessImpl::ApplySyscallFilter(const std::string& /*path*/) { } void ProcessImpl::EnterNewPidNamespace() { - // No-op, since ProcessImpl does not support sandboxing. + enter_new_pid_namespace_ = true; return; } @@ -167,8 +168,7 @@ bool ProcessImpl::PopulatePipeMap() { bool ProcessImpl::IsFileDescriptorInPipeMap(int fd) const { for (const auto& pipe : pipe_map_) { - if (fd == pipe.second.parent_fd_ || - fd == pipe.second.child_fd_ || + if (fd == pipe.second.parent_fd_ || fd == pipe.second.child_fd_ || fd == pipe.first) { return true; } @@ -203,8 +203,8 @@ bool ProcessImpl::Start() { if (arguments_.empty()) { return false; } - std::unique_ptr<char* []> argv = - std::make_unique<char* []>(arguments_.size() + 1); + std::unique_ptr<char*[]> argv = + std::make_unique<char*[]>(arguments_.size() + 1); for (size_t i = 0; i < arguments_.size(); ++i) argv[i] = const_cast<char*>(arguments_[i].c_str()); @@ -216,113 +216,138 @@ bool ProcessImpl::Start() { return false; } - pid_t pid = fork(); - int saved_errno = errno; - if (pid < 0) { - LOG(ERROR) << "Fork failed: " << saved_errno; - Reset(0); - return false; + // 64K child stack size + constexpr size_t kStackSize = 64 * 1024; + // clone() expects a pointer which points to top most byte of the stack + auto stack = reinterpret_cast<char*>(mmap(nullptr, + kStackSize, + PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, + -1, + 0)) + + kStackSize; + struct State { + ProcessImpl* p; + char** argv; + } state{}; + state.p = this; + state.argv = argv.get(); + int flags = SIGCHLD; + if (enter_new_pid_namespace_) { + flags |= CLONE_NEWPID; } - - if (pid == 0) { - // Executing inside the child process. - // Close unused file descriptors. - if (close_unused_file_descriptors_) { - CloseUnusedFileDescriptors(); + int pid = clone( + [](void* arg) { + State* s = reinterpret_cast<State*>(arg); + s->p->ExecChildProcess(s->argv); + return 0; + }, + stack, + flags, + &state); + + // Still executing inside the parent process with known child pid. + arguments_.clear(); + UpdatePid(pid); + // Close our copy of child side pipes only if we created those pipes. + for (const auto& i : pipe_map_) { + if (!i.second.is_bound_) { + IGNORE_EINTR(close(i.second.child_fd_)); } + } + return true; +} - base::InjectiveMultimap fd_shuffle; - for (const auto& it : pipe_map_) { - // Close parent's side of the child pipes. - if (it.second.parent_fd_ != -1) - IGNORE_EINTR(close(it.second.parent_fd_)); +void ProcessImpl::ExecChildProcess(char** argv) { +#ifdef __BIONIC__ + // Disable fdsan and fdtrack post-fork, so we don't falsely trigger on + // processes that fork, close all of their fds, and then exec. + android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_DISABLED); +#endif + // Executing inside the child process. + // Close unused file descriptors. + if (close_unused_file_descriptors_) { + CloseUnusedFileDescriptors(); + } - fd_shuffle.emplace_back(it.second.child_fd_, it.first, true); - } + base::InjectiveMultimap fd_shuffle; + for (const auto& it : pipe_map_) { + // Close parent's side of the child pipes. + if (it.second.parent_fd_ != -1) + IGNORE_EINTR(close(it.second.parent_fd_)); - if (!base::ShuffleFileDescriptors(&fd_shuffle)) { - PLOG(ERROR) << "Could not shuffle file descriptors"; - _exit(kErrorExitStatus); - } + fd_shuffle.emplace_back(it.second.child_fd_, it.first, true); + } - if (!input_file_.empty()) { - int input_handle = - HANDLE_EINTR(open(input_file_.c_str(), - O_RDONLY | O_NOFOLLOW | O_NOCTTY)); - if (input_handle < 0) { - PLOG(ERROR) << "Could not open " << input_file_; - // Avoid exit() to avoid atexit handlers from parent. - _exit(kErrorExitStatus); - } + if (!base::ShuffleFileDescriptors(&fd_shuffle)) { + PLOG(ERROR) << "Could not shuffle file descriptors"; + _exit(kErrorExitStatus); + } - // It's possible input_handle is already stdin. But if not, we need - // to dup into that file descriptor and close the original. - if (input_handle != STDIN_FILENO) { - if (HANDLE_EINTR(dup2(input_handle, STDIN_FILENO)) < 0) { - PLOG(ERROR) << "Could not dup fd to stdin for " << input_file_; - _exit(kErrorExitStatus); - } - IGNORE_EINTR(close(input_handle)); - } + if (!input_file_.empty()) { + int input_handle = HANDLE_EINTR( + open(input_file_.c_str(), O_RDONLY | O_NOFOLLOW | O_NOCTTY)); + if (input_handle < 0) { + PLOG(ERROR) << "Could not open " << input_file_; + // Avoid exit() to avoid atexit handlers from parent. + _exit(kErrorExitStatus); } - if (!output_file_.empty()) { - int output_handle = HANDLE_EINTR(open( - output_file_.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, - 0666)); - if (output_handle < 0) { - PLOG(ERROR) << "Could not create " << output_file_; - // Avoid exit() to avoid atexit handlers from parent. + // It's possible input_handle is already stdin. But if not, we need + // to dup into that file descriptor and close the original. + if (input_handle != STDIN_FILENO) { + if (HANDLE_EINTR(dup2(input_handle, STDIN_FILENO)) < 0) { + PLOG(ERROR) << "Could not dup fd to stdin for " << input_file_; _exit(kErrorExitStatus); } - HANDLE_EINTR(dup2(output_handle, STDOUT_FILENO)); - HANDLE_EINTR(dup2(output_handle, STDERR_FILENO)); - // Only close output_handle if it does not happen to be one of - // the two standard file descriptors we are trying to redirect. - if (output_handle != STDOUT_FILENO && output_handle != STDERR_FILENO) { - IGNORE_EINTR(close(output_handle)); - } + IGNORE_EINTR(close(input_handle)); } - if (gid_ != static_cast<gid_t>(-1) && setresgid(gid_, gid_, gid_) < 0) { - int saved_errno = errno; - LOG(ERROR) << "Unable to set GID to " << gid_ << ": " << saved_errno; - _exit(kErrorExitStatus); - } - if (uid_ != static_cast<uid_t>(-1) && setresuid(uid_, uid_, uid_) < 0) { - int saved_errno = errno; - LOG(ERROR) << "Unable to set UID to " << uid_ << ": " << saved_errno; - _exit(kErrorExitStatus); - } - if (!pre_exec_.Run()) { - LOG(ERROR) << "Pre-exec callback failed"; + } + + if (!output_file_.empty()) { + int output_handle = HANDLE_EINTR(open( + output_file_.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, 0666)); + if (output_handle < 0) { + PLOG(ERROR) << "Could not create " << output_file_; + // Avoid exit() to avoid atexit handlers from parent. _exit(kErrorExitStatus); } - // Reset signal mask for the child process if not inheriting signal mask - // from the parent process. - if (!inherit_parent_signal_mask_) { - sigset_t signal_mask; - CHECK_EQ(0, sigemptyset(&signal_mask)); - CHECK_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, nullptr)); + HANDLE_EINTR(dup2(output_handle, STDOUT_FILENO)); + HANDLE_EINTR(dup2(output_handle, STDERR_FILENO)); + // Only close output_handle if it does not happen to be one of + // the two standard file descriptors we are trying to redirect. + if (output_handle != STDOUT_FILENO && output_handle != STDERR_FILENO) { + IGNORE_EINTR(close(output_handle)); } - if (search_path_) { - execvp(argv[0], &argv[0]); - } else { - execv(argv[0], &argv[0]); - } - PLOG(ERROR) << "Exec of " << argv[0] << " failed"; + } + if (gid_ != static_cast<gid_t>(-1) && setresgid(gid_, gid_, gid_) < 0) { + int saved_errno = errno; + LOG(ERROR) << "Unable to set GID to " << gid_ << ": " << saved_errno; + _exit(kErrorExitStatus); + } + if (uid_ != static_cast<uid_t>(-1) && setresuid(uid_, uid_, uid_) < 0) { + int saved_errno = errno; + LOG(ERROR) << "Unable to set UID to " << uid_ << ": " << saved_errno; + _exit(kErrorExitStatus); + } + if (!pre_exec_.Run()) { + LOG(ERROR) << "Pre-exec callback failed"; _exit(kErrorExitStatus); + } + // Reset signal mask for the child process if not inheriting signal mask + // from the parent process. + if (!inherit_parent_signal_mask_) { + sigset_t signal_mask; + CHECK_EQ(0, sigemptyset(&signal_mask)); + CHECK_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, nullptr)); + } + if (search_path_) { + execvp(argv[0], &argv[0]); } else { - // Still executing inside the parent process with known child pid. - arguments_.clear(); - UpdatePid(pid); - // Close our copy of child side pipes only if we created those pipes. - for (const auto& i : pipe_map_) { - if (!i.second.is_bound_) { - IGNORE_EINTR(close(i.second.child_fd_)); - } - } + execv(argv[0], &argv[0]); } - return true; + PLOG(ERROR) << "Exec of " << argv[0] << " failed"; + _exit(kErrorExitStatus); } int ProcessImpl::Wait() { @@ -341,8 +366,8 @@ int ProcessImpl::Wait() { // kill the process that has just exited. UpdatePid(0); if (!WIFEXITED(status)) { - DCHECK(WIFSIGNALED(status)) << old_pid - << " neither exited, nor died on a signal?"; + DCHECK(WIFSIGNALED(status)) + << old_pid << " neither exited, nor died on a signal?"; LOG(ERROR) << "Process " << old_pid << " did not exit normally: " << WTERMSIG(status); return -1; diff --git a/brillo/process.h b/brillo/process.h index d69d38b..49e2a8c 100644 --- a/brillo/process.h +++ b/brillo/process.h @@ -202,7 +202,7 @@ class BRILLO_EXPORT ProcessImpl : public Process { // Is this an input or output pipe from child's perspective. bool is_input_; // Is this a bound (pre-existing) file descriptor? - bool is_bound_; + bool is_bound_ = false; }; typedef std::map<int, PipeInfo> PipeMap; @@ -214,6 +214,7 @@ class BRILLO_EXPORT ProcessImpl : public Process { bool IsFileDescriptorInPipeMap(int fd) const; void CloseUnusedFileDescriptors(); + void ExecChildProcess(char**); // Pid of currently managed process or 0 if no currently managed // process. pid must not be modified except by calling @@ -237,6 +238,8 @@ class BRILLO_EXPORT ProcessImpl : public Process { // parent process when starting the child process, which avoids leaking // unnecessary file descriptors to the child process. bool close_unused_file_descriptors_; + // Whether to create this process in a new PID namespace. + bool enter_new_pid_namespace_ = false; }; } // namespace brillo diff --git a/brillo/secure_allocator.h b/brillo/secure_allocator.h index de0b348..ad0036b 100644 --- a/brillo/secure_allocator.h +++ b/brillo/secure_allocator.h @@ -53,7 +53,6 @@ namespace brillo { template <typename T> class BRILLO_PRIVATE SecureAllocator : public std::allocator<T> { public: - using typename std::allocator<T>::pointer; using typename std::allocator<T>::size_type; using typename std::allocator<T>::value_type; @@ -75,8 +74,8 @@ class BRILLO_PRIVATE SecureAllocator : public std::allocator<T> { size_type max_size() const { return max_size_; } // Allocation: allocate ceil(size/pagesize) for holding the data. - pointer allocate(size_type n, pointer hint = nullptr) { - pointer buffer = nullptr; + value_type* allocate(size_type n, value_type* hint = nullptr) { + value_type* buffer = nullptr; // Check if n can be theoretically allocated. CHECK_LT(n, max_size()); @@ -97,7 +96,7 @@ class BRILLO_PRIVATE SecureAllocator : public std::allocator<T> { size_type buffer_size = CalculatePageAlignedBufferSize(n); // Memory locking granularity is per-page: mmap ceil(size/page size) pages. - buffer = reinterpret_cast<pointer>( + buffer = reinterpret_cast<value_type*>( mmap(nullptr, buffer_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); if (buffer == MAP_FAILED) @@ -155,7 +154,7 @@ class BRILLO_PRIVATE SecureAllocator : public std::allocator<T> { clear_contents(p, sizeof(U)); } - virtual void deallocate(pointer p, size_type n) { + virtual void deallocate(value_type* p, size_type n) { // Check if n can be theoretically deallocated. CHECK_LT(n, max_size()); @@ -182,7 +181,7 @@ class BRILLO_PRIVATE SecureAllocator : public std::allocator<T> { #endif // Zero-out all bytes in the allocated buffer. - virtual void __attribute_no_opt clear_contents(pointer v, size_type n) { + virtual void __attribute_no_opt clear_contents(value_type* v, size_type n) { if (!v) return; memset(v, 0, n); diff --git a/brillo/secure_blob_test.cc b/brillo/secure_blob_test.cc index 871c79c..8a4a1e8 100644 --- a/brillo/secure_blob_test.cc +++ b/brillo/secure_blob_test.cc @@ -232,14 +232,13 @@ TEST_F(SecureBlobTest, HexStringToSecureBlob) { template <typename T> class TestSecureAllocator : public SecureAllocator<T> { public: - using typename SecureAllocator<T>::pointer; using typename SecureAllocator<T>::size_type; using typename SecureAllocator<T>::value_type; int GetErasedCount() { return erased_count; } protected: - void clear_contents(pointer p, size_type n) override { + void clear_contents(value_type* p, size_type n) override { SecureAllocator<T>::clear_contents(p, n); unsigned char *v = reinterpret_cast<unsigned char*>(p); for (int i = 0; i < n; i++) { |