Sandboxed API Explained

The Sandboxed API (SAPI) builds on top of the well-established Sandbox2 project. This page explains the design architecture of SAPI and key concepts.

Overview

SAPI is designed to provide developers with tools to prepare C/C++ libraries for sandboxing, as well as with the APIs necessary for communication with the sandboxed version of the C/C++ libraries.

This diagram shows the architecture of a SAPI sandboxed C/C++ library:

SAPI Diagram

SAPI also provides primitives for manual and automatic (based on custom pointer attributes) memory synchronization (arrays, structures) between the SAPI Libraries and the host code.

Finally, a high-level Transactions API enables monitoring SAPI Libraries, and restarts them if they fail (e.g., due to security violations, crashes, or resource exhaustion).

Sandbox2

The open-source project Sandbox2 is developed and maintained by Google security engineers and is the core sandboxing technology used by SAPI. Sandbox2 contains three main components, the Sandbox Policy, the Executor, and the Sandboxee.

Sandbox Policy

The sandbox policy defines the restricted execution environment for the Sandboxed Library. This is achieved by clarifying which syscalls can be executed. SAPI uses the same mechanism as Sandbox2, see the Sandbox Policy section and the Getting Started page for Sandbox2 for more information on how to design and define a sandbox policy.

SAPI uses a default policy, alternatively you can use a dedicated sandbox policy by defining it in a sandbox.h header file and passing it as an argument in the sapi_library build rule.

Sandboxed Library

This is the sandboxed C/C++ library that will be executed in the restricted sandbox environment provided by Sandbox2. Ultimately, the Sandboxed Library exposes the required functionality which can be consumed by the Host Code.

The Sandboxed Library is built with the sapi_library build rule, in which you can specify a customized sandbox policy that defines the restricted execution environment. Depending on the library, you may have to write wrapper or stub code (see libcurl), but you are not expected to change the source code of the C/C++ library while preparing the SAPI version.

SAPI Object and RPC Stub

SAPI Object is a C++ object that exposes the API of the Sandboxed Library. It forwards calls from Host Code to RPC Stub, which is embedded in SAPI Library along with the Sandboxed Library.

These two elements are automatically generated by the build system using the sapi_library() build rule. SAPI supports two build systems, Google's Bazel and CMake.

Host Code

The Host Code is what implements the logic provided by the SAPI library. It's what would otherwise consume the unsandboxed version of the C/C++ library. As such, the Host Code calls functions exported by the SAPI library, passing data to and receiving data from the sandbox.

The Host Code needs to be adapted to use the SAPI library. Most notably, calling the functions of the library is not possible because the library lives in a separate sandboxed process. Therefore, SAPI provides tools which create a SAPI object that proxies calls to a SAPI library.

Concepts

Bazel Build Rules

The SAPI project provides two Bazel build rules for sandboxing a C/C++ library:

  • sapi_library() – Creates all the outputs which are necessary to have the C/C++ library sandboxed as a Sandbox2 Sandboxee. The build output can be used as a dependency for the cc_binary() rule used to build the host code binary.
  • sapi_interface() – Auto-generates the header that can be included in the host code binary.

For a more exhaustive explanation of the Build Rules, see Build Rules.

Variables

SAPI provides a number of special types, called SAPI Types, that we recommend using in the Host Code. The primary reason that SAPI Types are needed is because of the process, and thus memory, isolation between the Host Code and the Sandboxed Library.

For a more exhaustive explanation of this topic and an overview of some commonly used SAPI Types, see Variables.

Transactions

As explained above, any API call to a Sandboxed Library is passed over an RPC layer. To be able to handle a failure on this layer, you need to implement appropriate error handling. The SAPI Transaction module provides the necessary mechanism to make sure that all calls to a Sandboxed Library are completed without any RPC-level problems, or are returned with a relevant error.

For a more exhaustive explanation of this topic, see Transactions.

Getting started

Read our Getting Started page to set up your first Sandboxed API project.