Getting Started With Sandboxed API

On this page, you will learn how to create your own sandboxed C/C++ library with Sandboxed API (SAPI). Use it as a guide alongside the examples and code documentation in the header files.

Build Dependencies

The following dependencies must be installed on the system:

  • Linux kernel with support for UTS, IPC, user, PID, and network namespaces
  • Linux userspace API headers
  • To compile your code: GCC 6 (version 7 or higher preferred) or Clang 7 (or higher)
  • For auto-generating header files: Clang Python Bindings
  • Python 3.5 or later
  • Bazel version 2.2.0 or CMake version 3.12 or higher.
    • CMake only: GNU Make or a version of the libcap library headers and a build tool such as Ninja (recommended).

Using Bazel

Bazel is the recommended build system and is the easiest to integrate with.

Our documentation uses the Clang compiler. If you need a specific toolchain (e.g. compiler, linker, etc.), refer to the Bazel documentation for information on how to change the default compiler toolchain.

Debian 10 (Buster)

To install build dependencies:

echo "deb stable jdk1.8" | \
  sudo tee /etc/apt/sources.list.d/bazel.list
wget -qO - | 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


Kernel options required:

General setup  --->
-*- Namespaces support
[*]   UTS namespace
[*]   IPC namespace
[*]   User namespace (EXPERIMENTAL)
[*]   PID Namespaces
[*]   Network namespace

To install build dependencies:

emerge dev-util/bazel dev-python/typing dev-python/clang-python

Using CMake

CMake is a popular open-source meta build system that generates project files for build tools such as Ninja or Make.

Debian 10 (Buster)

To install build dependencies:

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


Kernel options required:

General setup  --->
-*- Namespaces support
[*]   UTS namespace
[*]   IPC namespace
[*]   User namespace (EXPERIMENTAL)
[*]   PID Namespaces
[*]   Network namespace

To install build dependencies:

emerge sys-kernel/linux-headers dev-util/cmake dev-util/ninja \

Development Process

To sandbox a C/C++ library, you will have to prepare two items for your project:

You may be familiar with the zlib from the Sandbox2 examples here a whole program (zpipe.c) was sandboxed. In the following steps, you will learn how to use SAPI to sandbox the zlib library and make use of the Sandboxed Library.

1. Decide which functions are needed

If you look at the zlib host code (, you can see that the tool's functionality is to read data from stdin and use zlib's deflate() function to compress the data until an EOF marker is read. In total, the program uses three functions from zlib:

  • deflateInit_(): To initialize for compression
  • deflate(): To perform the compression operation on the data chunk
  • deflateEnd(): To end the compression and free dynamically allocated data structures

In a real life example you would review the C/C++ library and decide which functions are needed. A possible strategy is to start with the Host Code and use the library unsandboxed. Then, in a second step, you could generate the Sandboxed Library and adapt the Host Code to use the sandboxed function calls.

2. Write the sapi_library Build Rule

After you have identified the three zlib functions that are needed from the sandboxed zlib library, you can define the build rule in the BUILD file. The documentation for the sapi_library build rule can be found on the Build Rules page.

The code snippet below shows the sapi_library definition for the zlib SAPI example. Using the lib attribute, Bazel is instructed to look in the WORKSPACE file for the zlib library.

    name = "zlib-sapi",
    srcs = [],
    hdrs = [],
    functions = [
    lib = "@net_zlib//:zlib",
    lib_name = "Zlib",
    namespace = "sapi::zlib",

The result is that the sandboxed zlib library is generated. The output is the SAPI Object which can be included into the Host Code and be used to communicate with the sandboxed library via RPC calls. The Sandbox Policy used in this example is the default policy.

3. Write or Change the Host Code

It's now time to incorporate the generated SAPI Library into the Host Code.

Create the Sandbox

Use sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create()); to create a sandbox object.

Use sapi::zlib::ZlibApi api(&sandbox); to instantiate the SAPI Object and thus make the sandboxed functions available for use.

Use SAPI Types

SAPI Types are special types in the form of C++ classes that SAPI provides because sometimes regular C-types will not work.

The first use of a SAPI type can be observed in the declaration of strm, where a SAPI Struct is used: sapi::v::Struct<sapi::zlib::z_stream> strm;

The template type (sapi::zlib::z_stream) is a good example of code automatically generated by the build rule.

Take a look at the Variables page for more details.

Make API Calls

To make calls to either defalteInit_, deflate, or deflateEnd, use the SAPI Object. If you decide to use the ‘change' approach, you have to make sure that the function parameters match the expected values.

An example of each of the calls in the zlib example:

  • api.deflateInit_(strm.PtrBoth(), Z_DEFAULT_COMPRESSION,
        version.PtrBefore(), sizeof(sapi::zlib::z_stream));
  • api.deflate(strm.PtrBoth(), flush);
  • api.deflateEnd(strm.PtrBoth()).IgnoreError();

Using SAPI Transactions

SAPI isolates the Host Code from the Sandboxed Library and gives the caller the ability to restart or abort problematic data processing requests. SAPI Transaction goes one step further and automatically repeats failed processes.

Take a look at the SAPI Transactions Page for more details.


Under Examples you can find a few libraries, already prepared by the SAPI team.