我可以使用线程吗?
可以,Sandbox2 支持线程。
所有线程都必须沙盒化
由于 Linux 的工作方式,seccomp-bpf 政策仅应用于当前线程:这意味着该政策不会应用于其他现有线程,但未来的线程将继承该政策:
- 如果您在第一种模式中使用 Sandbox2,即在
execve()
之前启用沙盒,则所有线程都会继承该政策,不会出现问题。这是首选的沙盒模式。 - 如果您使用的是第二种模式(执行器具有
set_enable_sandbox_before_exec(false)
,并且 Sandboxee 通过SandboxMeHere()
告知执行器何时需要沙盒化),请确保将过滤条件应用于所有线程。否则,可能会出现沙盒逃逸风险:恶意代码可能会从沙盒线程迁移到非沙盒线程。
我应该如何编译我的 Sandboxee?
与静态关联的可执行文件相比,将沙盒进程编译为动态关联的可执行文件会导致需要列入许可名单的系统调用(例如 open
/openat
、mmap
等)显著增加。由于在运行时调用动态链接器来加载共享库,因此需要所有这些额外的系统调用。
不过,对于静态链接的沙盒进程,虽然需要列入许可名单的系统调用更少,但也存在安全隐患;ASLR 堆熵从 30 位减少到 8 位,这使得漏洞利用更容易。
这种两难困境基本上可以归结为:
- 动态:堆 ASLR 效果好,可能更难获取初始代码执行权限,但代价是沙盒政策效果较差,可能更容易突破。
- 静态:堆 ASLR 较差,可能更容易获得初始代码执行权限,但沙盒政策更有效,可能更难突破。
从历史上看,静态链接的二进制文件不支持位置无关代码 (pie
)。此外,Bazel 默认添加了 pie
。为了能够定义严格的系统调用过滤条件,您必须覆盖 Bazel 的默认值。
编译器经过多年的改进,现在支持 static-pie
选项。
使用此选项时,系统会指示编译器生成位置无关的代码,但与 pie
相比,此选项现在还包括所有静态链接的库。从安全角度来看,static-pie
仍会降低 ASLR 熵(从 30 位降至 14 位),但与之前没有 pie
的情况相比,这已有所改进。
由于 Bazel 默认添加 pie
,而静态与其不兼容,因此请考虑使用链接器选项标志将 -static-pie
链接器标志传递给 cc_binary 规则并覆盖默认设置:
linkstatic = 1,
linkopts=["-static-pie"],
如需查看这些选项的示例,请参阅 static 示例 BUILD:static_bin.cc 与 static-pie
静态链接,这使得可以制定非常严格的系统调用政策。此方法还非常适合对第三方二进制文件进行沙盒处理。
我可以对 32 位 x86 二进制文件进行沙盒处理吗?
Sandbox2 只能沙盒化与编译时相同的架构。
此外,Sandbox2 已不再支持 32 位 x86。如果您尝试使用 64 位 x86 执行器来沙盒化 32 位 x86 二进制文件,或者使用发出 32 位系统调用的 64 位 x86 二进制文件(通过 int 0x80),则两者都会生成沙盒违规,可以通过架构标签 [X86-32] 来识别。
此行为背后的原因是,系统调用编号在不同架构之间有所不同,并且由于系统调用政策是在执行器的架构中编写的,因此允许沙盒进程使用不同的架构会很危险。事实上,这可能会导致允许看似无害的系统调用,但实际上,这意味着另一个更具危害性的系统调用可能会打开沙盒以实现逃逸。
执行器进程可以请求的沙盒数量是否有限制?
对于每个 Sandboxee 实例(从 forkserver 派生的新进程),系统都会创建一个新线程,这就是限制所在之处。
执行器能否请求创建多个沙盒?
不能。Executor 实例与 Sandboxee 之间存在 1:1 的关系,前者存储 Sandboxee 的 PID,管理 Comms 实例与 Sandbox 实例之间的通信等。
为什么我在 forkserver.cc 中收到“Function not implemented”错误?
Sandbox2 仅支持在较新的内核上运行。我们目前的截止版本是 3.19 内核,但未来可能会发生变化。这是因为我们使用了相对较新的内核功能,包括带有 TSYNC 标志的用户命名空间和 seccomp。
如果您在生产环境中运行,这应该不是问题,因为几乎整个舰队都在运行足够新的内核。如果您对此有任何疑问,请与我们联系。
如果您使用的是 Debian 或 Ubuntu,只需运行以下命令即可轻松更新内核:
sudo apt-get install linux-image-<RECENT_VERSION>