5. 與 Sandboxee 通訊
根據預設,執行程式可以透過檔案描述元與 Sandboxee 通訊。這可能會派上用場,例如,只想與沙箱分享檔案,或讀取 Sandboxee 的標準輸出內容。
但您很可能需要執行程式和 Sandboxee 之間更複雜的通訊邏輯。comms 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()
建立通訊端配對端點。這可用於讀取沙箱傳送的標準輸出內容或標準錯誤。可以在工具中查看使用範例。// The executor receives a file descriptor of the sandboxee stdout int recv_fd1 = executor->ipc())->ReceiveFd(STDOUT_FILENO);
使用通訊 API
Sandbox2 提供便利的通訊 API。以簡單又輕鬆的方式,在執行器和 Sandboxee 之間共用整數、字串或位元組緩衝區。以下是 crc4 範例中的部分程式碼片段。
如要開始使用 comms API,您必須先從 Sandbox2 物件取得 comms 物件:
sandbox2::Comms* comms = s2.comms();
一旦通訊對像有可用的通訊物件,即可使用 Send* 系列函式將資料傳送給沙箱。您可以在 crc4 範例中找到 comms 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()
和沙箱中的 comms->RecvFD()
將其傳遞給沙箱。
在下方程式碼片段中,您會看到執行程式的一面。沙箱會以非同步方式執行,並透過緩衝區與沙箱分享資料:
// 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());
在沙箱的端,您還必須建立緩衝區物件,並從執行者傳送的檔案描述元讀取資料:
// 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 */