### Run Sandboxed API String Operation Example Source: https://developers.google.com/code-sandboxing/sandboxed-api Executes a sample string operation example provided by Sandboxed API using Bazel. ```bash bazel run //sandboxed_api/examples/stringop:main_stringop ``` -------------------------------- ### Start Custom ForkServer (Custom Forkserver) Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started Initiate a custom ForkServer to prepare a binary for sandboxing and wait for fork requests from the executor. ```cpp #include "sandboxed_api/sandbox2/executor.h" // Start the custom ForkServer std::string path = "path/to/binary"; std::vector args = {path}; auto fork_executor = absl::make_unique(path, args); fork_executor->StartForkServer(); // Initialize Executor with Comms channel to the ForkServer auto executor = absl::make_unique( fork_executor->ipc()->GetComms()); ``` -------------------------------- ### Initialize Custom ForkServer Source: https://developers.google.com/code-sandboxing/sandbox2/getting-started Starts a custom forkserver and initializes the executor with the communication channel. ```cpp #include "sandboxed_api/sandbox2/executor.h" // Start the custom ForkServer std::string path = "path/to/binary"; std::vector args = {path}; auto fork_executor = absl::make_unique(path, args); fork_executor->StartForkServer(); // Initialize Executor with Comms channel to the ForkServer auto executor = absl::make_unique( fork_executor->ipc()->GetComms()); ``` -------------------------------- ### Install Bazel Dependencies on Gentoo Source: https://developers.google.com/code-sandboxing/sandboxed-api/getting-started Installs necessary build tools and Python libraries for Bazel on Gentoo. ```bash emerge dev-util/bazel dev-python/typing dev-python/clang-python ``` -------------------------------- ### Enable Sandboxing During Runtime (Sandbox2 Forkserver) Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started After initialization, notify the executor to start sandboxing by calling `sandbox2_client.SandboxMeHere()`. Ensure this is always called for safety. ```cpp // main() of sandboxee int main(int argc, char** argv) { gflags::ParseCommandLineFlags(&argc, &argv, false); // Set-up the sandbox2::Client object, using a file descriptor (1023). sandbox2::Comms comms(sandbox2::Comms::kSandbox2ClientCommsFD); sandbox2::Client sandbox2_client(&comms); // Enable sandboxing from here. sandbox2_client.SandboxMeHere(); … ``` -------------------------------- ### Normal Library Use Example Source: https://developers.google.com/code-sandboxing/sandboxed-api/transactions This pattern is typical for projects without sandboxed libraries, involving initialization, data processing, and cleanup. ```c++ LibInit(); while (data = NextDataToProcess()) { result += LibProcessData(data); } LibClose(); ``` -------------------------------- ### SAPI Array Initialization Source: https://developers.google.com/code-sandboxing/sandboxed-api/variables Example of wrapping a native C array into a SAPI Array object for use in sandboxed library calls. ```APIDOC ## SAPI Array Initialization ### Description Wraps a native C array into a `::sapi::v::Array` object to allow memory access within the sandboxed process. ### Request Example ```cpp int arr[3] = {1, 2, 3}; sapi::v::Array sarr(arr, ABSL_ARRAYSIZE(arr)); ``` ``` -------------------------------- ### Install Dependencies for Sandboxed API (Debian 10) Source: https://developers.google.com/code-sandboxing/sandboxed-api Installs necessary dependencies for Sandboxed API on Debian 10 Buster, including build tools, Bazel, and Clang. ```bash echo "deb http://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list wget -qO - https://bazel.build/bazel-release.pub.gpg | sudo apt-key add - sudo apt-get update sudo apt-get install -qy build-essential linux-libc-dev bazel python3 python3-pip libclang-7-dev pip3 install clang ``` -------------------------------- ### Install CMake Dependencies on Gentoo Source: https://developers.google.com/code-sandboxing/sandboxed-api/getting-started Installs necessary build tools and Python libraries for CMake on Gentoo. ```bash emerge sys-kernel/linux-headers dev-util/cmake dev-util/ninja \ dev-python/clang-python ``` -------------------------------- ### Install Bazel Dependencies on Debian Source: https://developers.google.com/code-sandboxing/sandboxed-api/getting-started Installs necessary build tools and libraries for Bazel on Debian 10 (Buster). Includes build-essential, kernel headers, Bazel, Python, and Clang. ```bash echo "deb http://storage.googleapis.com/bazel-apt stable jdk1.8" | \ sudo tee /etc/apt/sources.list.d/bazel.list wget -qO - https://bazel.build/bazel-release.pub.gpg | sudo apt-key add - sudo apt-get update sudo apt-get install -qy build-essential linux-libc-dev bazel python3 \ python3-pip libclang-dev pip3 install clang ``` -------------------------------- ### Install CMake Dependencies on Debian Source: https://developers.google.com/code-sandboxing/sandboxed-api/getting-started Installs necessary build tools and libraries for CMake on Debian 10 (Buster). Includes build-essential, kernel headers, CMake, Ninja, Python, and Clang. ```bash sudo apt-get install -qy build-essential linux-libc-dev cmake ninja-build \ python3 python3-pip libclang-dev libcap-dev pip3 install absl-py clang ``` -------------------------------- ### Sandboxed Library Initialization and Execution Source: https://developers.google.com/code-sandboxing/sandboxed-api/transactions Demonstrates initializing, finishing, and processing data with a sandboxed library using SAPI transactions and callbacks. Ensure `LibraryAPI` and `SAPI_RETURN_IF_ERROR` are available. ```cpp // Overwrite the Init method, passed to BasicTransaction initialization ::absl::Status Init(::sapi::Sandbox* sandbox) { // Instantiate the SAPI Object LibraryAPI lib(sandbox); // Instantiate the Sandboxed Library SAPI_RETURN_IF_ERROR(lib.LibInit()); return ::absl::OkStatus(); } // Overwrite the Finish method, passed to BasicTransaction initialization ::absl::Status Finish(::sapi::Sandbox *sandbox) { // Instantiate the SAPI Object LibraryAPI lib(sandbox); // Clean-up sandboxed library instance SAPI_RETURN_IF_ERROR(lib.LibClose()); return ::absl::OkStatus(); } // Wrapper function to process data, passed to Run method call ::absl::Status HandleData(::sapi::Sandbox *sandbox, Data data_to_process, Result *out) { // Instantiate the SAPI Object LibraryAPI lib(sandbox); // Call the sandboxed function LibProcessData SAPI_ASSIGN_OR_RETURN(*out, lib.LibProcessData(data_to_process)); return ::absl::OkStatus(); } void Handle() { // Use SAPI Transactions by passing function pointers to ::sapi::BasicTransaction ::sapi::BasicTransaction transaction(Init, Finish); while (data = NextDataToProcess()) { ::sandbox2::Result result; // call the ::sapi::Transaction::Run() method transaction.Run(HandleData, data, &result); // ... } // ... } ``` -------------------------------- ### Execute Binary with Sandbox Enabled (C++) Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started?hl=fr This is the simplest method for sandboxing a binary. It's recommended when you don't have the source code. Ensure the path to the binary and its arguments are correctly specified. The environment is inherited from the parent process. ```cpp #include "sandboxed_api/sandbox2/executor.h" std::string path = "path/to/binary"; std::vector args = {path}; // args[0] will become the sandboxed // process' argv[0], typically the // path to the binary. auto executor = absl::make_unique(path, args); ``` -------------------------------- ### Allowing Static and Dynamic Startup Syscalls Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started?hl=it Use these utility functions to allow static or dynamic process startup system calls. ```cpp AllowStaticStartup(); ``` ```cpp AllowDynamicStartup(); ``` -------------------------------- ### Define a Sandbox Policy with PolicyBuilder Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started Demonstrates how to construct a policy using helper functions, argument-specific syscall filtering, and error-based blocking. ```cpp #include "sandboxed_api/sandbox2/policy.h" #include "sandboxed_api/sandbox2/policybuilder.h" #include "sandboxed_api/sandbox2/util/bpf_helper.h" std::unique_ptr CreatePolicy() { return sandbox2::PolicyBuilder() .AllowSyscall(__NR_read) // See also AllowRead() .AllowTime() // Allow time, gettimeofday and clock_gettime .AddPolicyOnSyscall(__NR_write, { ARG(0), // fd is the first argument of write (argument #0) JEQ(1, ALLOW), // allow write only on fd 1 KILL, // kill if not fd 1 }) .AddPolicyOnSyscall(__NR_mprotect, { ARG_32(2), // prot is a 32-bit wide argument, so it's OK to use *_32 // macro here JNE32(PROT_READ | PROT_WRITE, KILL), // prot must be the RW, otherwise // kill the process ARG(1), // len is a 64-bit argument JNE(0x1000, KILL), // Allow single page syscalls only, otherwise kill // the process ALLOW, // Allow for the syscall to proceed, if prot and // size match }) // Allow the openat() syscall but always return "not found". .BlockSyscallWithErrno(__NR_openat, ENOENT) .BuildOrDie(); } ``` -------------------------------- ### Initialize Stand-alone Sandbox Executor Source: https://developers.google.com/code-sandboxing/sandbox2/getting-started/executor Use this method to sandbox an entire binary without requiring source code modifications. It is the safest approach as it avoids unsandboxed initialization. ```cpp #include "sandboxed_api/sandbox2/executor.h" std::string path = "path/to/binary"; std::vector args = {path}; // args[0] will become the sandboxed // process' argv[0], typically the // path to the binary. auto executor = absl::make_unique(path, args); ``` -------------------------------- ### Initialize SAPI Array Source: https://developers.google.com/code-sandboxing/sandboxed-api/variables Shows constructors for wrapping existing arrays and dynamically creating new arrays. ```cpp int arr[10]; sapi::v::Array iarr(arr, ABSL_ARRAYSIZE(arr)); ``` ```cpp sapi::v::Array buffer(PNG_IMAGE_SIZE(*image.mutable_data())); ``` -------------------------------- ### Allowing Specific Syscalls with PolicyBuilder Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started?hl=it Use AllowSyscall to permit a single system call or AllowSyscalls for multiple. This example allows read and time-related syscalls. ```cpp #include "sandboxed_api/sandbox2/policy.h" #include "sandboxed_api/sandbox2/policybuilder.h" #include "sandboxed_api/sandbox2/util/bpf_helper.h" std::unique_ptr CreatePolicy() { return sandbox2::PolicyBuilder() .AllowSyscall(__NR_read) // See also AllowRead() .AllowTime() // Allow time, gettimeofday and clock_gettime .AddPolicyOnSyscall(__NR_write, { ARG(0), // fd is the first argument of write (argument #0) JEQ(1, ALLOW), // allow write only on fd 1 KILL, // kill if not fd 1 }) .AddPolicyOnSyscall(__NR_mprotect, { ARG_32(2), // prot is a 32-bit wide argument, so it's OK to use *_32 // macro here JNE32(PROT_READ | PROT_WRITE, KILL), // prot must be the RW, otherwise // kill the process ARG(1), // len is a 64-bit argument JNE(0x1000, KILL), // Allow single page syscalls only, otherwise kill // the process }) .Build(); } ``` -------------------------------- ### Adding File System Access Rules Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started?hl=it Use AddFile, AddDirectory, or AddTmpfs to manage file system access within the sandbox. ```cpp AddFile("/path/to/your/file"); AddDirectory("/path/to/your/directory"); AddTmpfs("/path/to/tmpfs"); ``` -------------------------------- ### Update Linux kernel on Debian or Ubuntu Source: https://developers.google.com/code-sandboxing/sandbox2/faq Install a recent kernel version to ensure compatibility with required features like user namespaces and seccomp TSYNC. ```bash sudo apt-get install linux-image- ``` -------------------------------- ### Get Comms Object Source: https://developers.google.com/code-sandboxing/sandbox2/getting-started/communication?hl=es-419 Obtain the Comms object from the Sandbox2 object to enable communication between the executor and Sandboxee. This object is the entry point for sending and receiving various data types. ```cpp sandbox2::Comms* comms = s2.comms(); ``` -------------------------------- ### Run Sandbox2 Tool Source: https://developers.google.com/code-sandboxing/sandbox2/examples Commands to execute the sandbox2tool using different build systems. ```bash bazel run //sandboxed_api/sandbox2/examples/tool:sandbox2tool -- \ --sandbox2tool_resolve_and_add_libraries \ --sandbox2tool_additional_bind_mounts /etc \ /bin/cat /etc/hostname ``` ```bash cd build-dir ninja sandbox2_sandbox2tool && \ ./sandbox2_sandbox2tool \ --sandbox2tool_resolve_and_add_libraries \ --sandbox2tool_additional_bind_mounts /etc \ /bin/cat /etc/hostname ``` ```bash blaze run //third_party/sandboxed_api/sandbox2/examples/tool:sandbox2tool -- \ --sandbox2tool_resolve_and_add_libraries \ --sandbox2tool_additional_bind_mounts /etc \ /bin/cat /etc/hostname ``` -------------------------------- ### Disable Sandbox During Initialization (Sandbox2 Forkserver) Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started Use this to allow the program to execute in an unsandboxed manner during initialization. Call `set_enable_sandbox_before_exec(false)` on the executor. ```cpp #include "sandboxed_api/sandbox2/executor.h" std::string path = "path/to/binary"; std::vector args = {path}; auto executor = absl::make_unique(path, args); executor->set_enable_sandbox_before_exec(false); ``` -------------------------------- ### Execute SAPI API Calls Source: https://developers.google.com/code-sandboxing/sandboxed-api/getting-started Demonstrates how to invoke sandboxed functions using the SAPI object interface. ```cpp api.deflateInit_(strm.PtrBoth(), Z_DEFAULT_COMPRESSION, version.PtrBefore(), sizeof(sapi::zlib::z_stream)); ``` ```cpp api.deflate(strm.PtrBoth(), flush); ``` ```cpp api.deflateEnd(strm.PtrBoth()).IgnoreError(); ``` -------------------------------- ### Executor: Send Buffer Data to Sandboxee Source: https://developers.google.com/code-sandboxing/sandbox2/getting-started/communication Use this code on the executor side to create a buffer, fill it with data, and send its file descriptor to the Sandboxee using `comms->SendFD()`. Ensure the buffer is created with sufficient size. ```cpp // start the sandbox asynchronously s2.RunAsync(); // instantiate the comms object sandbox2::Comms* comms = s2.comms(); // random buffer data we want to send constexpr unsigned char buffer_data[] = /* random data */; constexpr unsigned int buffer_dataLen = 34; // create sandbox2 buffer absl::StatusOr> buffer = sandbox2::Buffer::CreateWithSize(1ULL << 20 /* 1Mib */); std::unique_ptr buffer_ptr = std::move(buffer).value(); // point to the sandbox2 buffer and fill with data uint8_t* buf = buffer_ptr‑>data(); memcpy(buf, buffer_data, buffer_data_len); // send the data to the sandboxee comms‑>SendFd(buffer_ptr‑>fd()); ``` -------------------------------- ### Allowing Open, Read, and Write Syscalls Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started?hl=it Utility functions to permit open, read, and write system calls for the sandboxee. ```cpp AllowOpen(); ``` ```cpp AllowRead(); ``` ```cpp AllowWrite(); ``` -------------------------------- ### Configure static-pie linking in Bazel Source: https://developers.google.com/code-sandboxing/sandbox2/faq Use these options in a cc_binary rule to enable static-pie, which improves ASLR entropy compared to standard static linking. ```starlark linkstatic = 1, linkopts=["-static-pie"], ``` -------------------------------- ### Configure Sandbox2 Forkserver Executor Source: https://developers.google.com/code-sandboxing/sandbox2/getting-started/executor Allows for unsandboxed initialization by disabling the sandbox before execution. Requires the process to be single-threaded. ```cpp #include "sandboxed_api/sandbox2/executor.h" std::string path = "path/to/binary"; std::vector args = {path}; auto executor = absl::make_unique(path, args); executor->set_enable_sandbox_before_exec(false); ``` -------------------------------- ### Adding Libraries for a Binary Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started?hl=it Automatically include necessary libraries and the linker for a given binary using AddLibrariesForBinary. ```cpp AddLibrariesForBinary("/path/to/your/binary"); ``` -------------------------------- ### Share Data Buffers (Executor Side) Source: https://developers.google.com/code-sandboxing/sandbox2/getting-started Create and send a buffer to the Sandboxee to avoid expensive data copies. ```cpp // start the sandbox asynchronously s2.RunAsync(); // instantiate the comms object sandbox2::Comms* comms = s2.comms(); // random buffer data we want to send constexpr unsigned char buffer_data[] = /* random data */; constexpr unsigned int buffer_dataLen = 34; // create sandbox2 buffer absl::StatusOr> buffer = sandbox2::Buffer::CreateWithSize(1ULL << 20 /* 1Mib */); std::unique_ptr buffer_ptr = std::move(buffer).value(); // point to the sandbox2 buffer and fill with data uint8_t* buf = buffer_ptr‑>data(); memcpy(buf, buffer_data, buffer_data_len); // send the data to the sandboxee comms‑>SendFd(buffer_ptr‑>fd()); ``` -------------------------------- ### Static Binary Sandboxing with File Descriptor Mapping Source: https://developers.google.com/code-sandboxing/sandbox2/examples?hl=es-419 Isolates a statically linked binary without source code. It demonstrates mapping a file descriptor into the sandboxee and allowing specific system calls to fail gracefully. ```cpp #include "sandbox2/sandbox2.h" #include "sandbox2/client.h" #include "sandbox2/config.h" #include "sandbox2/util.h" #include #include #include // For STDIN_FILENO int main(int argc, char** argv) { // Initialize Sandbox2 sandbox2::Sandbox2 sandbox( sandbox2::CreateSandboxConfig(argv[0])); // Get the path to the static binary std::string static_bin_path = sandbox2::GetDataDependencyFilePath( "sandbox2/examples/static_bin.bin"); // Get the client to communicate with the Sandboxee sandbox2::Client* client = sandbox2->get_client(); // Map /proc/version into the sandboxee int fd = open("/proc/version", O_RDONLY); if (fd == -1) { std::cerr << "Failed to open /proc/version." << std::endl; return 1; } if (!client->MapFd(fd, "/proc/version")) { std::cerr << "Failed to map file descriptor." << std::endl; close(fd); return 1; } close(fd); // Close the original fd, it's now mapped // Send input to the Sandboxee via stdin std::string input_text = "hello world"; if (!client->SendBytes(input_text.c_str(), input_text.length(), STDIN_FILENO)) { std::cerr << "Failed to send input to Sandboxee." << std::endl; return 1; } // Receive output from the Sandboxee (assuming it writes to stdout) std::string output_text; if (!client->RecvBytes(&output_text)) { std::cerr << "Failed to receive output from Sandboxee." << std::endl; return 1; } std::cout << "Sandboxee output: " << output_text << std::endl; return 0; } ``` ```cpp #include #include #include // For std::transform #include // For std::toupper int main() { std::string line; while (std::getline(std::cin, line)) { std::transform(line.begin(), line.end(), line.begin(), ::toupper); std::cout << line << std::endl; } return 0; } ``` -------------------------------- ### Synchronous Sandbox Execution and Result Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started Run a sandbox synchronously and log its final execution status upon completion. No additional termination step is needed. ```cpp Sandbox2::Result result = s2.Run(); LOG(INFO) << "Final execution status: " << result.ToString(); ``` -------------------------------- ### Clone and Build Sandboxed API Source: https://developers.google.com/code-sandboxing/sandboxed-api Clones the Sandboxed API repository from GitHub and initiates the build process using Bazel. ```bash git clone https://github.com/google/sandboxed-api && cd sandboxed-api bazel build … ``` -------------------------------- ### SAPI Status and Macro Usage for Error Handling Source: https://developers.google.com/code-sandboxing/sandboxed-api/transactions Illustrates using `::sapi::StatusOr` and `SAPI_ASSIGN_OR_RETURN` for handling potential errors from sandboxed functions. Requires `status_macro.h`. ```cpp // Instead of void, use ::sapi::Status ::sapi::Status SumTransaction::Main() { // Instantiate the SAPI Object SumApi f(sandbox()); // ::sapi::StatusOr sum(int a, int b) SAPI_ASSIGN_OR_RETURN(int v, f.sum(1000, 337)); // ... // ::sapi::Status sums(sapi::v::Ptr* params) SumParams params; params.mutable_data()->a = 1111; params.mutable_data()->b = 222; params.mutable_data()->ret = 0; SAPI_RETURN_IF_ERROR(f.sums(params.PtrBoth())); // ... // Gets symbol address and prints its value int *ssaddr; SAPI_RETURN_IF_ERROR(sandbox()->Symbol( "sumsymbol", reinterpret_cast(&ssaddr))); ::sapi::v::Int sumsymbol; sumsymbol.SetRemote(ssaddr); SAPI_RETURN_IF_ERROR(sandbox()->TransferFromSandboxee(&sumsymbol)); // ... return ::sapi::OkStatus(); } ``` -------------------------------- ### Sandboxee: Receive Buffer Data via File Descriptor Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started Receive a file descriptor from the executor, create a buffer from it, and access the shared data. ```cpp // establish the communication with the executor int fd; comms.RecvFD(&fd); // create the buffer absl::StatusOr> buffer = sandbox2::Buffer::createFromFd(fd); // get the data auto buffer_ptr = std::move(buffer).value(); uint8_t* buf = buffer_ptr->data(); /* work with the buf object */ ``` -------------------------------- ### SAPI Pointer Synchronization Methods Source: https://developers.google.com/code-sandboxing/sandboxed-api/variables Overview of methods used to synchronize memory between Host and Sandboxed processes. ```APIDOC ## SAPI Pointer Synchronization ### Description Methods used to control memory synchronization when passing pointers to sandboxed API functions. ### Pointer Methods - **PtrNone()**: No synchronization performed. - **PtrBefore()**: Synchronizes memory from Host to Sandboxed process before the call. - **PtrAfter()**: Synchronizes memory from Sandboxed to Host process after the call. - **PtrBoth()**: Synchronizes memory in both directions (Before and After). ``` -------------------------------- ### Receive Data Buffers (Sandboxee Side) Source: https://developers.google.com/code-sandboxing/sandbox2/getting-started Receive a file descriptor from the executor and reconstruct the buffer object. ```cpp // establish the communication with the executor int fd; comms.RecvFD(&fd); // create the buffer absl::StatusOr> buffer = sandbox2::Buffer::createFromFd(fd); // get the data auto buffer_ptr = std::move(buffer).value(); uint8_t* buf = buffer_ptr‑>data(); /* work with the buf object */ ``` -------------------------------- ### Create Custom Sandbox Policy Source: https://developers.google.com/code-sandboxing/sandbox2/getting-started Defines a custom sandbox policy using PolicyBuilder, allowing specific syscalls like read and time, and applying conditional policies on write and mprotect. It also demonstrates blocking the openat syscall to always return 'not found'. ```cpp #include "sandboxed_api/sandbox2/policy.h" #include "sandboxed2/policybuilder.h" #include "sandboxed_api/sandbox2/util/bpf_helper.h" std::unique_ptr CreatePolicy() { return sandbox2::PolicyBuilder() .AllowSyscall(__NR_read) // See also AllowRead() .AllowTime() // Allow time, gettimeofday and clock_gettime .AddPolicyOnSyscall(__NR_write, { ARG(0), // fd is the first argument of write (argument #0) JEQ(1, ALLOW), // allow write only on fd 1 KILL, }) .AddPolicyOnSyscall(__NR_mprotect, { ARG_32(2), // prot is a 32-bit wide argument, so it's OK to use *_32 // macro here JNE32(PROT_READ | PROT_WRITE, KILL), // prot must be the RW, otherwise // kill the process ARG(1), // len is a 64-bit argument JNE(0x1000, KILL), // Allow single page syscalls only, otherwise kill // the process ALLOW, // Allow for the syscall to proceed, if prot and // size match }) // Allow the openat() syscall but always return "not found". .BlockSyscallWithErrno(__NR_openat, ENOENT) .BuildOrDie(); } ``` -------------------------------- ### Asynchronous Sandbox Execution Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started Run the sandbox without blocking, allowing for concurrent communication with the Sandboxee. ```cpp #include "sandboxed_api/sandbox2/sandbox2.h" sandbox2::Sandbox2 s2(std::move(executor), std::move(policy)); if (s2.RunAsync()) { // Communicate with sandboxee, use s2.Kill() to kill it if needed // ... } Sandbox2::Result result = s2.AwaitResult(); LOG(INFO) << "Final execution status: " << result.ToString(); ``` -------------------------------- ### Sandboxee: Receive and Read Buffer Data from Executor Source: https://developers.google.com/code-sandboxing/sandbox2/getting-started/communication On the Sandboxee side, use this code to receive the file descriptor sent by the executor using `comms.RecvFD()`, create a buffer from it, and access the data. This avoids data copying. ```cpp // establish the communication with the executor int fd; comms.RecvFD(&fd); // create the buffer absl::StatusOr> buffer = sandbox2::Buffer::createFromFd(fd); // get the data auto buffer_ptr = std::move(buffer).value(); uint8_t* buf = buffer_ptr‑>data(); /* work with the buf object */ ``` -------------------------------- ### Create a Custom Sandbox Policy Source: https://developers.google.com/code-sandboxing/sandbox2/getting-started/sandbox-policy Defines a custom sandbox policy by allowing specific syscalls like read and time, adding conditional policies for write and mprotect based on arguments, and blocking the openat syscall. This policy is built using PolicyBuilder. ```cpp #include "sandboxed_api/sandbox2/policy.h" #include "sandboxed_api/sandbox2/policybuilder.h" #include "sandboxed_api/sandbox2/util/bpf_helper.h" std::unique_ptr CreatePolicy() { return sandbox2::PolicyBuilder() .AllowSyscall(__NR_read) // See also AllowRead() .AllowTime() // Allow time, gettimeofday and clock_gettime .AddPolicyOnSyscall(__NR_write, { ARG(0), // fd is the first argument of write (argument #0) JEQ(1, ALLOW), // allow write only on fd 1 KILL, // kill if not fd 1 }) .AddPolicyOnSyscall(__NR_mprotect, { ARG_32(2), // prot is a 32-bit wide argument, so it's OK to use *_32 // macro here JNE32(PROT_READ | PROT_WRITE, KILL), // prot must be the RW, otherwise // kill the process ARG(1), // len is a 64-bit argument JNE(0x1000, KILL), // Allow single page syscalls only, otherwise kill // the process ALLOW, // Allow for the syscall to proceed, if prot and // size match }) // Allow the openat() syscall but always return "not found". .BlockSyscallWithErrno(__NR_openat, ENOENT) .BuildOrDie(); } ``` -------------------------------- ### Executor: Send Buffer Data via File Descriptor Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started Share data with the Sandboxee asynchronously by creating a buffer, filling it with data, and sending its file descriptor using SendFd. ```cpp // start the sandbox asynchronously s2.RunAsync(); // instantiate the comms object sandbox2::Comms* comms = s2.comms(); // random buffer data we want to send constexpr unsigned char buffer_data[] = /* random data */; constexpr unsigned int buffer_dataLen = 34; // create sandbox2 buffer absl::StatusOr> buffer = sandbox2::Buffer::CreateWithSize(1ULL << 20 /* 1Mib */); std::unique_ptr buffer_ptr = std::move(buffer).value(); // point to the sandbox2 buffer and fill with data uint8_t* buf = buffer_ptr->data(); memcpy(buf, buffer_data, buffer_data_len); // send the data to the sandboxee comms->SendFd(buffer_ptr->fd()); ``` -------------------------------- ### Map File Descriptors with MapFd Source: https://developers.google.com/code-sandboxing/sandbox2/getting-started/communication?hl=es-419 Use `MapFd()` to map file descriptors from the executor to the Sandboxee, allowing the sharing of open files. This is useful for providing input files to the Sandboxee. ```cpp // The executor opened /proc/version and passes it to the sandboxee as stdin executor->ipc()->MapFd(proc_version_fd, STDIN_FILENO); ``` -------------------------------- ### Synchronous Sandbox Execution Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started Instantiate the Sandbox2 object and block execution until a result is returned. ```cpp #include "sandboxed_api/sandbox2/sandbox2.h" sandbox2::Sandbox2 s2(std::move(executor), std::move(policy)); sandbox2::Result result = s2.Run(); // Synchronous LOG(INFO) << "Result of sandbox execution: " << result.ToString(); ``` -------------------------------- ### Asynchronous Sandbox Kill and Await Result Source: https://developers.google.com/code-sandboxing/sandbox2/full-getting-started Terminate an asynchronously running sandbox using Kill, then await its result. This is recommended even if the sandbox might terminate on its own. ```cpp s2.Kill(); sandbox2::Result result = s2.AwaitResult(); LOG(INFO) << "Final execution status: " << result.ToString(); ```