aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSandboxed API Team <sandboxed-api@google.com>2024-05-08 07:07:27 -0700
committerCopybara-Service <copybara-worker@google.com>2024-05-08 07:08:30 -0700
commit3cdbf526f3856dbae95b840f6c8df75b5f7afdbd (patch)
treedb152ac793f8fa593c3342f17cd243ef0b63d725
parent69bc13545d5627af1d3f6fc4dd464f9b8f3d2883 (diff)
downloadsandboxed-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.cc97
-rw-r--r--sandboxed_api/sandbox.h38
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