5. Berkomunikasi dengan Sandboxee

Secara default, eksekutor dapat berkomunikasi dengan Sandboxee melalui deskriptor file. Ini mungkin yang Anda butuhkan, misalnya jika Anda hanya ingin berbagi file dengan Sandboxee, atau membaca output standar Sandboxee.

Namun, kemungkinan besar Anda membutuhkan logika komunikasi yang lebih kompleks antara eksekutor dan Sandboxee. comms API (lihat file header comms.h) dapat digunakan untuk mengirim bilangan bulat, string, buffer byte, protobuf, atau deskriptor file.

Membagikan Deskripsi File

Dengan Inter-Process Communication API (lihat ipc.h), Anda dapat menggunakan MapFd() atau ReceiveFd():

  • Gunakan MapFd() untuk memetakan deskripsi file dari eksekutor ke Sandboxee. Fungsi ini dapat digunakan untuk membagikan file yang dibuka dari eksekutor untuk digunakan di Sandboxee. Contoh penggunaan dapat dilihat di statis.

    // The executor opened /proc/version and passes it to the sandboxee as stdin
    executor->ipc()->MapFd(proc_version_fd, STDIN_FILENO);
    
  • Gunakan ReceiveFd() untuk membuat endpoint socketpair. Ini dapat digunakan untuk membaca output standar atau error standar Sandboxee. Contoh penggunaan dapat dilihat di alat.

    // The executor receives a file descriptor of the sandboxee stdout
    int recv_fd1 = executor->ipc())->ReceiveFd(STDOUT_FILENO);
    

Menggunakan API komunikasi

Sandbox2 menyediakan API komunikasi yang praktis. Ini adalah cara sederhana dan mudah untuk membagikan bilangan bulat, string, atau buffering byte antara eksekutor dan Sandboxee. Berikut adalah beberapa cuplikan kode yang dapat Anda temukan dalam contoh crc4.

Untuk memulai API komunikasi, Anda harus mendapatkan objek komunikasi dari objek Sandbox2 terlebih dahulu:

sandbox2::Comms* comms = s2.comms();

Setelah objek komunikasi tersedia, data dapat dikirim ke Sandboxee menggunakan salah satu kelompok fungsi Kirim*. Anda dapat menemukan contoh penggunaan API komunikasi dalam contoh crc4. Cuplikan kode di bawah ini menunjukkan kutipan dari contoh tersebut. Eksekutor mengirimkan unsigned char buf[size] dengan SendBytes(buf, size):

if (!(comms->SendBytes(static_cast<const uint8_t*>(buf), sz))) {
  /* handle error */
}

Untuk menerima data dari Sandboxee, gunakan salah satu fungsi Recv*. Cuplikan kode di bawah adalah kutipan dari contoh crc4. Eksekutor menerima checksum dalam bilangan bulat tanpa tanda tangan 32-bit: uint32_t crc4;

if (!(comms->RecvUint32(&crc4))) {
  /* handle error */
}

Berbagi Data dengan {i>Buffer<i}

Fungsi berbagi data lainnya adalah menggunakan API buffer untuk berbagi data dalam jumlah besar dan menghindari salinan yang mahal yang dikirim bolak-balik antara eksekutor dan Sandboxee.

Eksekutor membuat Buffer, baik berdasarkan ukuran dan data yang akan diteruskan, atau langsung dari deskriptor file, dan meneruskannya ke Sandboxee menggunakan comms->SendFD() di eksekutor dan comms->RecvFD() di Sandboxee.

Dalam cuplikan kode di bawah, Anda dapat melihat sisi eksekutor. Sandbox berjalan secara asinkron dan berbagi data melalui buffering dengan 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());

Di sisi Sandboxee, Anda juga harus membuat objek buffer dan membaca data dari deskriptor file yang dikirim oleh eksekutor:

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