5. 与沙盒进程通信
默认情况下,执行器可以通过文件描述符与 Sandboxee 通信。这可能就是您需要的全部内容,例如,如果您只是想与 Sandboxee 共享文件,或者读取 Sandboxee 的标准输出。
不过,您很可能需要在执行器和 Sandboxee 之间实现更复杂的通信逻辑。通信 API(请参阅 comms.h 头文件)可用于发送整数、字符串、字节缓冲区、protobuf 或文件描述符。
共享文件描述符
使用进程间通信 API(请参阅 ipc.h),您可以使用 MapFd()
或 ReceiveFd()
:
使用
MapFd()
将文件描述符从执行器映射到 Sandboxee。这可用于共享从执行程序打开的文件,以便在 Sandboxee 中使用。您可以在静态中查看使用示例。// The executor opened /proc/version and passes it to the sandboxee as stdin executor->ipc()->MapFd(proc_version_fd, STDIN_FILENO);
使用
ReceiveFd()
创建套接字对端点。可用于读取 Sandboxee 的标准输出或标准错误。您可以在工具中查看使用示例。// The executor receives a file descriptor of the sandboxee stdout int recv_fd1 = executor->ipc())->ReceiveFd(STDOUT_FILENO);
使用通信 API
Sandbox2 提供了一个便捷的 comms API。这是一种在执行器和 Sandboxee 之间共享整数、字符串或字节缓冲区的简单便捷的方式。以下是一些您可以在 crc4 示例中找到的代码段。
如需开始使用 Comms API,您必须先从 Sandbox2 对象获取 comms 对象:
sandbox2::Comms* comms = s2.comms();
通信对象可用后,可以使用 Send* 系列函数之一将数据发送到 Sandboxee。您可以在 crc4 示例中找到通信 API 的使用示例。以下代码段显示了该示例的摘录。执行器发送包含 SendBytes(buf, size)
的 unsigned char
buf[size]
:
if (!(comms->SendBytes(static_cast<const uint8_t*>(buf), sz))) {
/* handle error */
}
如需从 Sandboxee 接收数据,请使用某个 Recv*
函数。以下代码段摘自 crc4 示例。执行器以 32 位无符号整数的形式接收校验和:uint32_t crc4;
if (!(comms->RecvUint32(&crc4))) {
/* handle error */
}
与缓冲区共享数据
另一种数据共享功能是使用缓冲区 API 来共享大量数据,并避免在执行程序和 Sandboxee 之间来回发送的昂贵副本。
执行器通过大小和要传递的数据或直接从文件描述符创建缓冲区,并使用执行器中的 comms->SendFD()
和 Sandboxee 中的 comms->RecvFD()
将其传递给 Sandboxee。
在下面的代码段中,您可以看到执行者的部分。沙盒以异步方式运行,并通过缓冲区与 Sandboxee 共享数据:
// start the sandbox asynchronously
s2.RunAsync();
// instantiate the comms object
sandbox2::Comms* comms = s2.comms();
// random buffer data we want to send
constexpr unsigned char buffer_data[] = /* random data */;
constexpr unsigned int buffer_dataLen = 34;
// create sandbox2 buffer
absl::StatusOr<std::unique_ptr<sandbox2::Buffer>> buffer =
sandbox2::Buffer::CreateWithSize(1ULL << 20 /* 1Mib */);
std::unique_ptr<sandbox2::Buffer> buffer_ptr = std::move(buffer).value();
// point to the sandbox2 buffer and fill with data
uint8_t* buf = buffer_ptr‑>data();
memcpy(buf, buffer_data, buffer_data_len);
// send the data to the sandboxee
comms‑>SendFd(buffer_ptr‑>fd());
在 Sandboxee 端,您还必须创建一个缓冲区对象,并从执行器发送的文件描述符中读取数据:
// establish the communication with the executor
int fd;
comms.RecvFD(&fd);
// create the buffer
absl::StatusOr<std::unique_ptr<sandbox2::Buffer>> buffer =
sandbox2::Buffer::createFromFd(fd);
// get the data
auto buffer_ptr = std::move(buffer).value();
uint8_t* buf = buffer_ptr‑>data();
/* work with the buf object */