Sandboxed API 使用入门

在本页中,您将了解如何使用 Sandboxed API (SAPI) 创建自己的沙盒化 C/C++ 库。请将此页与 示例和 头文件中的代码文档一起用作指南。

构建依赖项

必须在系统上安装以下依赖项:

  • 支持 UTS、IPC、用户、PID 和网络命名空间的 Linux 内核
  • Linux 用户空间 API 标头
  • 如需编译代码:GCC 6(最好是 7 或更高版本)或 Clang 7(或更高版本)
  • 如需自动生成头文件:Clang Python 绑定
  • Python 3.5 或更高版本
  • Bazel 2.2.0 版或 CMake 3.12 版或更高版本。
    • 仅限 CMake:GNU Make 或 libcap 库标头的版本以及构建工具(例如Ninja,推荐使用)。

使用 Bazel

Bazel 是推荐的构建系统,也是最容易集成的系统。

我们的文档使用 Clang 编译器。如果您需要特定的工具链 (例如编译器、链接器等),请参阅 Bazel 文档,了解如何更改默认编译器工具链。

Debian 10 (Buster)

如需安装构建依赖项,请执行以下操作:

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

Gentoo

所需的内核选项:

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

如需安装构建依赖项,请执行以下操作:

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

使用 CMake

CMake 是一种常用的开源元构建系统,可为 Ninja 或 Make 等构建工具生成项目文件。

Debian 10 (Buster)

如需安装构建依赖项,请执行以下操作:

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

Gentoo

所需的内核选项:

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

如需安装构建依赖项,请执行以下操作:

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

开发流程

如需对 C/C++ 库进行沙盒化处理,您必须为项目准备两项内容:

您可能熟悉 Sandbox2 示例中的 zlib ,其中对整个程序 (zpipe.c) 进行了沙盒化处理。在以下步骤中,您将了解如何使用 SAPI 对 zlib 库进行沙盒化处理,并使用沙盒化库。

1. 确定需要哪些函数

如果您查看 zlib 宿主代码 (main_zlib.cc), 您会发现该工具的功能是从 stdin 读取数据,并使用 zlib 的 deflate() 函数压缩数据,直到读取 EOF 标记。该程序总共使用了 zlib 中的三个函数:

  • deflateInit_():用于初始化以进行压缩
  • deflate():用于对数据块执行压缩操作
  • deflateEnd():用于结束压缩并释放动态分配的数据结构

在实际示例中,您将查看 C/C++ 库并确定需要哪些函数。一种可能的策略是从宿主代码开始,并使用未沙盒化的库。然后,在第二步中,您可以生成沙盒化库并调整宿主代码以使用沙盒化函数调用。

2. 编写 sapi_library 构建规则

确定沙盒化 zlib 库中需要哪些 zlib 函数后,您可以在 BUILD 文件中定义构建规则。如需查看 sapi_library 构建规则的文档,请访问 构建规则页面。

以下代码段显示了 zlib SAPI 示例的 sapi_library 定义。使用 lib 属性,系统会指示 Bazel 在 WORKSPACE 文件 中查找 zlib 库。

sapi_library(
    name = "zlib-sapi",
    srcs = [],
    hdrs = [],
    functions = [
        "deflateInit_",
        "deflate",
        "deflateEnd",
    ],
    lib = "@net_zlib//:zlib",
    lib_name = "Zlib",
    namespace = "sapi::zlib",
)

结果是生成了沙盒化 zlib 库。输出是 SAPI 对象,该对象可以包含在宿主代码中,并用于通过 RPC 调用与沙盒化库进行通信。此示例中使用的沙盒政策是默认政策。

3. 编写或更改宿主代码

现在,您可以将生成的 SAPI 库合并到宿主代码中。

创建沙盒

使用 sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create()); 创建沙盒对象。

使用 sapi::zlib::ZlibApi api(&sandbox); 实例化 SAPI 对象,从而 使沙盒化函数可供使用。

使用 SAPI 类型

SAPI 类型是 SAPI 提供的特殊 类型,采用 C++ 类的形式,因为有时常规 C 类型不起作用。

您可以在 strm 的声明中观察到 SAPI 结构体的首次使用:sapi::v::Struct<sapi::zlib::z_stream> strm;

模板类型 (sapi::zlib::z_stream) 是构建规则自动生成的代码的一个很好的示例。

如需了解详情,请参阅变量页面

调用 API

如需调用 defalteInit_deflatedeflateEnd,请使用 SAPI 对象。如果您决定使用“更改”方法,则必须确保函数参数与预期值匹配。

以下是 zlib 示例中每个调用的示例:

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

使用 SAPI 事务

SAPI 将宿主代码与沙盒化库隔离开来,并让调用方能够重启或中止有问题的数据处理请求。SAPI 事务更进一步,会自动重复失败的进程。

如需了解详情,请参阅 SAPI 事务 页面

示例

示例 下,您可以找到一些 已由 SAPI 团队准备好的库。