diff options
author | Sandboxed API Team <sandboxed-api@google.com> | 2024-05-08 07:07:27 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2024-05-08 07:08:30 -0700 |
commit | 3cdbf526f3856dbae95b840f6c8df75b5f7afdbd (patch) | |
tree | db152ac793f8fa593c3342f17cd243ef0b63d725 | |
parent | 69bc13545d5627af1d3f6fc4dd464f9b8f3d2883 (diff) | |
download | sandboxed-api-upstream-main.tar.gz |
Add ForkClientContext holding a fork client and associated executor which canupstream-main
be shared between mutilple Sandbox objects.
PiperOrigin-RevId: 631788087
Change-Id: I352f473929ff22db183979253645031bc0bf93f1
-rw-r--r-- | sandboxed_api/sandbox.cc | 97 | ||||
-rw-r--r-- | sandboxed_api/sandbox.h | 38 |
2 files changed, 92 insertions, 43 deletions
diff --git a/sandboxed_api/sandbox.cc b/sandboxed_api/sandbox.cc index b73df43..9af16f8 100644 --- a/sandboxed_api/sandbox.cc +++ b/sandboxed_api/sandbox.cc @@ -28,6 +28,7 @@ #include <utility> #include <vector> +#include "sandboxed_api/file_toc.h" #include "absl/base/dynamic_annotations.h" #include "absl/base/macros.h" #include "absl/log/log.h" @@ -36,6 +37,7 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" #include "absl/time/time.h" #include "absl/types/span.h" #include "sandboxed_api/call.h" @@ -60,12 +62,26 @@ namespace sapi { +Sandbox::Sandbox(const FileToc* embed_lib_toc) { + owned_fork_client_context_ = + std::make_unique<ForkClientContext>(embed_lib_toc); + fork_client_context_ = owned_fork_client_context_.get(); +} + +Sandbox::Sandbox(std::nullptr_t) + : Sandbox(static_cast<const FileToc*>(nullptr)) {} + Sandbox::~Sandbox() { Terminate(); // The forkserver will die automatically when the executor goes out of scope // and closes the comms object. } +void Sandbox::SetForkClientContext(ForkClientContext* fork_client_context) { + fork_client_context_ = fork_client_context; + owned_fork_client_context_.reset(); +} + // A generic policy which should work with majority of typical libraries, which // are single-threaded and require ~30 basic syscalls. // @@ -158,45 +174,52 @@ absl::Status Sandbox::Init(bool use_unotify_monitor) { return absl::OkStatus(); } - // Initialize the forkserver if it is not already running. - if (!fork_client_) { - // If FileToc was specified, it will be used over any paths to the SAPI - // library. - std::string lib_path; - int embed_lib_fd = -1; - if (embed_lib_toc_ && !sapi::host_os::IsAndroid()) { - embed_lib_fd = EmbedFile::instance()->GetDupFdForFileToc(embed_lib_toc_); - if (embed_lib_fd == -1) { - PLOG(ERROR) << "Cannot create executable FD for TOC:'" - << embed_lib_toc_->name << "'"; - return absl::UnavailableError("Could not create executable FD"); + sandbox2::ForkClient* fork_client; + { + absl::MutexLock lock(&fork_client_context_->mu_); + // Initialize the forkserver if it is not already running. + if (!fork_client_context_->client_) { + // If FileToc was specified, it will be used over any paths to the SAPI + // library. + std::string lib_path; + int embed_lib_fd = -1; + const FileToc* embed_lib_toc = fork_client_context_->embed_lib_toc_; + if (embed_lib_toc && !sapi::host_os::IsAndroid()) { + embed_lib_fd = EmbedFile::instance()->GetDupFdForFileToc(embed_lib_toc); + if (embed_lib_fd == -1) { + PLOG(ERROR) << "Cannot create executable FD for TOC:'" + << embed_lib_toc->name << "'"; + return absl::UnavailableError("Could not create executable FD"); + } + lib_path = embed_lib_toc->name; + } else { + lib_path = PathToSAPILib(GetLibPath()); + if (lib_path.empty()) { + LOG(ERROR) << "SAPI library path is empty"; + return absl::FailedPreconditionError("No SAPI library path given"); + } } - lib_path = embed_lib_toc_->name; - } else { - lib_path = PathToSAPILib(GetLibPath()); - if (lib_path.empty()) { - LOG(ERROR) << "SAPI library path is empty"; - return absl::FailedPreconditionError("No SAPI library path given"); + std::vector<std::string> args = {lib_path}; + // Additional arguments, if needed. + GetArgs(&args); + std::vector<std::string> envs{}; + // Additional envvars, if needed. + GetEnvs(&envs); + + fork_client_context_->executor_ = + (embed_lib_fd >= 0) + ? std::make_unique<sandbox2::Executor>(embed_lib_fd, args, envs) + : std::make_unique<sandbox2::Executor>(lib_path, args, envs); + + fork_client_context_->client_ = + fork_client_context_->executor_->StartForkServer(); + + if (!fork_client_context_->client_) { + LOG(ERROR) << "Could not start forkserver"; + return absl::UnavailableError("Could not start the forkserver"); } } - std::vector<std::string> args = {lib_path}; - // Additional arguments, if needed. - GetArgs(&args); - std::vector<std::string> envs{}; - // Additional envvars, if needed. - GetEnvs(&envs); - - forkserver_executor_ = - (embed_lib_fd >= 0) - ? std::make_unique<sandbox2::Executor>(embed_lib_fd, args, envs) - : std::make_unique<sandbox2::Executor>(lib_path, args, envs); - - fork_client_ = forkserver_executor_->StartForkServer(); - - if (!fork_client_) { - LOG(ERROR) << "Could not start forkserver"; - return absl::UnavailableError("Could not start the forkserver"); - } + fork_client = fork_client_context_->client_.get(); } sandbox2::PolicyBuilder policy_builder; @@ -207,7 +230,7 @@ absl::Status Sandbox::Init(bool use_unotify_monitor) { auto s2p = ModifyPolicy(&policy_builder); // Spawn new process from the forkserver. - auto executor = std::make_unique<sandbox2::Executor>(fork_client_.get()); + auto executor = std::make_unique<sandbox2::Executor>(fork_client); executor // The client.cc code is capable of enabling sandboxing on its own. diff --git a/sandboxed_api/sandbox.h b/sandboxed_api/sandbox.h index 7c41921..c99b199 100644 --- a/sandboxed_api/sandbox.h +++ b/sandboxed_api/sandbox.h @@ -15,6 +15,7 @@ #ifndef SANDBOXED_API_SANDBOX_H_ #define SANDBOXED_API_SANDBOX_H_ +#include <cstddef> #include <cstdint> #include <ctime> #include <initializer_list> @@ -23,11 +24,14 @@ #include <vector> #include "sandboxed_api/file_toc.h" +#include "absl/base/attributes.h" #include "absl/base/macros.h" +#include "absl/base/thread_annotations.h" #include "absl/log/globals.h" #include "absl/log/log.h" #include "absl/status/status.h" #include "absl/status/statusor.h" +#include "absl/synchronization/mutex.h" #include "absl/time/time.h" #include "absl/types/span.h" #include "sandboxed_api/config.h" @@ -41,18 +45,40 @@ namespace sapi { +// Context holding, potentially shared, fork client. +class ForkClientContext { + public: + explicit ForkClientContext(const FileToc* embed_lib_toc) + : embed_lib_toc_(embed_lib_toc) {} + + private: + friend class Sandbox; + const FileToc* embed_lib_toc_; + absl::Mutex mu_; + std::unique_ptr<sandbox2::ForkClient> client_ ABSL_GUARDED_BY(mu_); + std::unique_ptr<sandbox2::Executor> executor_ ABSL_GUARDED_BY(mu_); +}; + // The Sandbox class represents the sandboxed library. It provides users with // means to communicate with it (make function calls, transfer memory). class Sandbox { public: - explicit Sandbox(const FileToc* embed_lib_toc) - : embed_lib_toc_(embed_lib_toc) {} + explicit Sandbox( + ForkClientContext* fork_client_context ABSL_ATTRIBUTE_LIFETIME_BOUND) + : fork_client_context_(fork_client_context) {} + + explicit Sandbox(const FileToc* embed_lib_toc ABSL_ATTRIBUTE_LIFETIME_BOUND); + + explicit Sandbox(std::nullptr_t); Sandbox(const Sandbox&) = delete; Sandbox& operator=(const Sandbox&) = delete; virtual ~Sandbox(); + void SetForkClientContext( + ForkClientContext* fork_client_context ABSL_ATTRIBUTE_LIFETIME_BOUND); + // Initializes a new sandboxing session. absl::Status Init(bool use_unotify_monitor = false); @@ -179,10 +205,6 @@ class Sandbox { // Exits the sandboxee. void Exit() const; - // The client to the library forkserver. - std::unique_ptr<sandbox2::ForkClient> fork_client_; - std::unique_ptr<sandbox2::Executor> forkserver_executor_; - // The main sandbox2::Sandbox2 object. std::unique_ptr<sandbox2::Sandbox2> s2_; // Marks whether Sandbox2 result was already fetched. @@ -203,6 +225,10 @@ class Sandbox { // FileTOC with the embedded library, takes precedence over GetLibPath if // present (not nullptr). const FileToc* embed_lib_toc_; + + ForkClientContext* fork_client_context_; + // Set if the object owns the client context instance. + std::unique_ptr<ForkClientContext> owned_fork_client_context_; }; } // namespace sapi |