diff options
author | Kelvin Zhang <zhangkelvin@google.com> | 2024-01-10 22:58:10 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2024-01-10 22:58:10 +0000 |
commit | 32a9a287af2d1a759c974f4e922ccb28c89f1d59 (patch) | |
tree | 6fec58eb135d4f9f75ae49cb9a57d285ed1da789 | |
parent | de2bba8da1f1b35765ff22ddca475698f9fd5f3f (diff) | |
parent | ef407734d9d3769169123f8907cf7f46380a8e1f (diff) | |
download | libbrillo-32a9a287af2d1a759c974f4e922ccb28c89f1d59.tar.gz |
Support entering a new PID namespace am: 6ea0027ef7 am: ef407734d9
Original change: https://android-review.googlesource.com/c/platform/external/libbrillo/+/2835005
Change-Id: I077c18c19fd1aa8b1c0745b819aef1a2b10edae7
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | brillo/process.cc | 206 | ||||
-rw-r--r-- | brillo/process.h | 5 |
2 files changed, 117 insertions, 94 deletions
diff --git a/brillo/process.cc b/brillo/process.cc index 54e91f0..5623db8 100644 --- a/brillo/process.cc +++ b/brillo/process.cc @@ -7,6 +7,7 @@ #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 +19,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> @@ -117,7 +117,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; } @@ -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,133 @@ 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) { + // 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)); - } - if (search_path_) { - execvp(argv[0], &argv[0]); - } else { - execv(argv[0], &argv[0]); + 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)); } - 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() { 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 |