1. 选择沙盒执行器方法
沙盒从执行器(请参阅沙盒执行器)开始,该执行器负责运行 Sandboxee。executor.h 头文件包含此用途所需的 API。此 API 非常灵活,让您可以选择最适合自己用例的方式。下面几部分介绍了您可以选择的 3 种不同方法。
方法 1:独立 - 在已启用沙盒的情况下执行二进制文件
这是使用沙盒的最简单方法。如果您要对没有源代码的整个二进制文件进行沙盒化处理,建议您使用此方法。这也是使用沙盒的最安全方式,因为没有可能造成不良影响的未沙盒化初始化。
在以下代码段中,我们定义了要沙盒化的二进制文件的路径,以及需要传递给 execve 系统调用的参数。在 executor.h 头文件中看到,我们没有为 envp
指定值,因此会从父级进程中复制环境。请记住,第一个参数始终是要执行的程序的名称,并且我们的代码段不会定义任何其他参数。
#include "sandboxed_api/sandbox2/executor.h"
std::string path = "path/to/binary";
std::vector<std::string> args = {path}; // args[0] will become the sandboxed
// process' argv[0], typically the
// path to the binary.
auto executor = absl::make_unique<sandbox2::Executor>(path, args);
方法 2:Sandbox2 Forkserver - 告知执行程序何时应沙盒化
通过此方法,您可以灵活地在初始化期间取消沙盒化,然后通过调用 ::sandbox2::Client::SandboxMeHere()
来选择何时进入沙盒模式。您需要能够在代码中定义何时想要启动沙盒,并且必须是单线程的(如需了解原因,请参阅常见问题解答)。
在以下代码段中,我们使用了与上述方法 1 中所述的相同代码。不过,为了让程序在初始化期间以未经过沙盒屏蔽的方式执行,我们会调用 set_enable_sandbox_before_exec(false)
。
#include "sandboxed_api/sandbox2/executor.h"
std::string path = "path/to/binary";
std::vector<std::string> args = {path};
auto executor = absl::make_unique<sandbox2::Executor>(path, args);
executor->set_enable_sandbox_before_exec(false);
由于执行器现在的沙盒已停用(在 Sandboxee 通知之前),因此我们必须创建一个 ::sandbox2::Client
实例,在执行器和 Sandboxee 之间建立通信,然后通知执行器初始化已完成,我们希望立即通过调用 sandbox2_client.SandboxMeHere()
启动沙盒化。
// main() of sandboxee
int main(int argc, char** argv) {
gflags::ParseCommandLineFlags(&argc, &argv, false);
// Set-up the sandbox2::Client object, using a file descriptor (1023).
sandbox2::Comms comms(sandbox2::Comms::kSandbox2ClientCommsFD);
sandbox2::Client sandbox2_client(&comms);
// Enable sandboxing from here.
sandbox2_client.SandboxMeHere();
…
此执行器方法的一个示例是 crc4,其中 crc4bin.cc
是 Sandboxee,它会在应进入沙盒时通知执行器 (crc4sandbox.cc
)。
方法 3:自定义 Forkserver - 准备二进制文件,等待分支请求,并自行沙盒
借助此模式,您可以启动二进制文件,为沙盒做好准备,并在二进制文件生命周期的特定时刻使其可供执行程序使用。
执行器将向您的二进制文件发送分支请求,该请求将执行 fork()
(通过 ::sandbox2::ForkingClient::WaitAndFork()
)。新创建的进程将可以使用 ::sandbox2::Client::SandboxMeHere()
进行沙盒化。
#include "sandboxed_api/sandbox2/executor.h"
// Start the custom ForkServer
std::string path = "path/to/binary";
std::vector<std::string> args = {path};
auto fork_executor = absl::make_unique<sandbox2::Executor>(path, args);
fork_executor->StartForkServer();
// Initialize Executor with Comms channel to the ForkServer
auto executor = absl::make_unique<sandbox2::Executor>(
fork_executor->ipc()->GetComms());
请注意,此模式非常复杂,仅在少数特定情况下适用;例如,当您有严格的内存要求时。您将受益于 COW,但缺点是没有真正的 ASLR。另一个典型的使用示例是,Sandboxee 需要进行长时间的 CPU 密集型初始化,可在处理不可信数据之前运行该过程。
如需查看此执行器方法的示例,请参阅 custom_fork。