常见问题解答

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

我可以使用话题吗?

可以,Sandbox2 支持会话。

所有线程都必须沙盒化

鉴于 Linux 的运作方式,seccomp-bpf 政策仅会应用于当前线程:这意味着,该策略不会应用于其他现有线程,但未来的线程会沿用该政策:

  • 如果您在 execve() 之前启用了沙盒功能的第一个模式下使用 Sandbox2,那么所有线程都将继承此政策,因此不会出现任何问题。这是沙盒的首选模式。
  • 如果您使用的是执行器具有 set_enable_sandbox_before_exec(false) 且沙盒模式希望通过 SandboxMeHere() 将执行沙盒告知执行器的第二模式,请确保过滤器已应用于所有线程。否则,会有沙盒转义的风险:恶意代码可能会从沙盒化的线程迁移到未沙盒化的线程。

我应如何编译沙盒?

如果不小心,很容易继承大量依赖项和附带效应(额外的系统调用、文件访问,甚至是网络连接),这会增加沙盒的难度(跟踪所有附带效应)和安全性(因为系统调用和文件政策更宽泛)。部分编译选项有助于减少此类问题:

  • 静态编译沙盒二进制文件,以避免使用大量系统调用(open/openatmmap 等)的动态链接。
  • 由于 Bazel 默认添加了 pie,但静态与之不兼容,因此请考虑使用功能标志通过 cc_binary 规则中的以下选项将其强制关闭:

    linkstatic = 1,
    features = [
        "fully_static_link",  # link libc statically
        "-pie",
    ],
    

然而:使用静态资源有助于减少 ASLR 堆熵(从 30 位减少到 8 位),让攻击变得更容易。根据沙盒的实现方式和政策谨慎决定哪一种方式更合适:

  • 并非静态:良好的堆 ASLR,可能很难执行初始代码,但代价是沙盒政策不太有效,因而可能会更容易被打破。
  • static:错误的堆 ASLR,可能更容易获取初始代码执行,但更有效的沙盒政策,可能更难突破。

遗憾的是,我们不支持此做法,因为编译器不支持静态 PIE(位置独立可执行文件)。PIE 是通过将二进制文件设为动态对象来实现的,并且动态加载器会在执行该文件之前在随机位置对其进行映射。然后,由于堆传统上是位于二进制文件基址之后的随机偏移量处(并使用 brk 系统调用进行扩展),这意味着对于静态二进制文件,堆 ASLR 熵仅此偏移量,因为没有 PIE。

如需查看这些编译选项的示例,请参阅静态示例 BUILD.bazelstatic_bin.cc 是静态编译的,这样我们就可以设置非常严格的系统调用政策。这也非常适合第三方二进制文件沙盒。

我可以对 32 位 x86 二进制文件进行沙盒化吗?

Sandbox2 只能沙盒化编译时所使用的架构。

此外,沙盒 2 也不再支持 32 位 x86。如果您尝试使用 64 位 x86 执行程序对 32 位 x86 二进制文件或 64 位 x86 二进制文件进行沙盒测试(通过 int 0x80)进行沙盒化处理,两者都会产生可通过架构标签 [X86-32] 识别的沙盒违规行为。

造成这种情况的原因在于,架构之间的系统调用编号有所不同,而且由于系统调用政策是用执行器的架构编写的,因此允许沙盒接受其他架构是非常危险的。事实上,这可能会导致系统调用看似无害的系统调用,实际上,这意味着另一种更有害的系统调用可能会使沙盒逃脱。

执行程序进程可以请求的沙盒数量是否有限制?

对于每个 Sandboxee 实例(从 Forkserver 衍生的新进程),系统会创建一个新线程 - 这就是限制所在。

执行器可以请求创建多个沙盒吗?

不是。具有一对一关系 - 执行器实例存储沙盒的 PID,管理沙盒实例与通信实例的通信等。

为什么我在 forkserver.cc 内看到“函数未实现”?

Sandbox2 仅支持在合理的新内核上运行。目前的终止函数是 3.19 内核,但将来可能会有所变化。这是因为我们使用了相对较新的内核功能,包括带有 TSYNC 标志的用户命名空间和 seccomp。

如果您在生产环境中运行,这应该没有问题,因为几乎整个机群都在运行新的足够内核。如果您对此有任何疑问,请与我们联系。

如果您在 Debian 或 Ubuntu 上运行,只需更新内核即可:

sudo apt-get install linux-image-<RECENT_VERSION>