5. 與 Sandboxee 通訊
依預設,執行器可以透過檔案描述元與 Sandboxee 通訊。舉例來說,如果您只想與 Sandboxee 分享檔案,或讀取 Sandboxee 的標準輸出內容,可能只需要這樣做。
不過,您很可能需要在執行器和 Sandboxee 之間建立更複雜的通訊邏輯。通訊 API (請參閱 comms.h 標頭檔) 可用於傳送整數、字串、位元組緩衝區、protobuf 或檔案描述元。
分享檔案描述元
使用 Inter-Process Communication 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()
建立 socketpair 端點。可用於讀取 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 範例中的一些程式碼片段。
如要開始使用通訊 API,請先從 Sandbox2 物件取得通訊物件:
sandbox2::Comms* comms = s2.comms();
通訊物件可用後,即可使用 Send* 系列函式,將資料傳送至 Sandboxee。您可以在 crc4 範例中找到通訊 API 的使用範例。以下程式碼片段是該範例的節錄內容。執行器會傳送含有 SendBytes(buf, size)
的 unsigned char
buf[size]
,並提供 SendBytes(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 */