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 */