在本页中,您将学习如何使用沙盒化 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 版或更高版本。
使用 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
热托语
所需内核选项:
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
热托语
所需内核选项:
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++ 库,您必须为项目准备两项内容:
- 沙盒化库
- 主机代码,以便使用沙盒库公开的功能。在构建流程中,SAPI 会自动为您生成 SAPI 对象和 RPC 存根。
您可能已经熟悉沙盒 2 中的示例 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
build 规则的文档,请参阅构建规则页面。
以下代码段显示了 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 类型不起作用。
首次使用 SAPI 类型时,可以在 strm
声明(其中使用 SAPI 结构体)中观察到:sapi::v::Struct<sapi::zlib::z_stream> strm;
模板类型 (sapi::zlib::z_stream
) 是 build 规则自动生成的代码示例。
如需了解详情,请查看“变量”页面。
进行 API 调用
若要调用 defalteInit_
、deflate
或 deflateEnd
,请使用 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 Transaction 会更进一步,自动重复失败的进程。
如需了解详情,请查看 SAPI 交易页面。
示例
在示例下面,您可以看到 SAPI 团队准备的一些库。