5. サンドボックス担当者とのやり取り
デフォルトでは、エグゼキュータはファイル記述子を介して Sandboxee と通信できます。Sandboxee とファイルを共有する場合や、Sandboxee の標準出力を読み取る場合などは、これらで十分です。
ただし、ほとんどの場合、エグゼキュータと Sandboxee の間にはより複雑な通信ロジックが必要になります。comms API(comms.h ヘッダー ファイルを参照)は、整数、文字列、バイトバッファ、protobuf、ファイル記述子を送信するために使用できます。
ファイル記述子の共有
Inter-Process Communication API(ipc.h を参照)を使用すると、MapFd()
または ReceiveFd()
を使用できます。
MapFd()
を使用して、エグゼキュータから Sandboxee にファイル記述子をマッピングします。これを使用して、Sandboxee で使用するためにエグゼキュータから開いたファイルを共有できます。使用例は、static で確認できます。// 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);
comms API の使用
Sandbox2 には、便利な通信 API が用意されています。これは、エグゼキュータと Sandboxee の間で整数、文字列、バイトバッファを簡単かつ簡単に共有できる方法です。crc4 のサンプルで、以下のコード スニペットを確認できます。
comms API の使用を開始するには、まず Sandbox2 オブジェクトから comms オブジェクトを取得する必要があります。
sandbox2::Comms* comms = s2.comms();
comms オブジェクトが使用可能になると、Send* ファミリー関数のいずれかを使用して Sandboxee にデータを送信できます。comms API の使用例は、crc4 のサンプルをご覧ください。以下のコード スニペットは、この例からの抜粋を示しています。エグゼキュータは 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 */
}
バッファを使用してデータを共有する
もう 1 つのデータ共有機能は、バッファ API を使用して大量のデータを共有し、エグゼキュータと Sandboxee の間でコストの高いコピーが送受信されることを回避することです。
エグゼキュータは、サイズとデータによって、またはファイル記述子から直接 Buffer を作成し、エグゼキュータの 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 */