5. Sandboxee ile iletişim kurma

Varsayılan olarak yürütücü, dosya tanımlayıcıları üzerinden Sandboxee ile iletişim kurabilir. Örneğin, bir dosyayı Korumalı Alan ile paylaşmak veya Korumalı Alan'ın standart çıkışını okumak istiyorsanız bunu yapmanız gerekebilir.

Ancak muhtemelen yürütücü ile Sandboxee'nin arasında daha karmaşık bir iletişim mantığına ihtiyacınız vardır. comms API'si (comms.h başlık dosyasına bakın) tam sayılar, dizeler, bayt arabellekleri, protobuflar veya dosya açıklayıcıları göndermek için kullanılabilir.

Dosya Açıklayıcılarını Paylaşma

Inter-Process Communication API'sini (ipc.h) kullanarak MapFd() veya ReceiveFd() kullanabilirsiniz:

  • Yürütücüdeki dosya tanımlayıcılarını Sandboxee ile eşlemek için MapFd() kullanın. Bu özellik, yürütücüden açılan bir dosyayı Sandboxee'de kullanılmak üzere paylaşmak için kullanılabilir. Statik bir öğede örnek bir kullanım görülebilir.

    // The executor opened /proc/version and passes it to the sandboxee as stdin
    executor->ipc()->MapFd(proc_version_fd, STDIN_FILENO);
    
  • Yuva çifti uç noktası oluşturmak için ReceiveFd() kullanın. Bu değer, Sandboxee'nin standart çıkışını veya standart hatalarını okumak için kullanılabilir. Örnek bir kullanımı araçta görebilirsiniz.

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

İletişim API'sini kullanma

Sandbox2, kullanışlı bir iletişim API'si sağlar. Bu, tam sayıları, dizeleri veya bayt arabelleklerini yürütücü ile Sandboxee arasında paylaşmanın basit ve kolay bir yoludur. Aşağıda crc4 örneğinde bulabileceğiniz bazı kod snippet'leri verilmiştir.

comms API'yi kullanmaya başlamak için ilk olarak Sandbox2 nesnesinden iletişim nesnesini almanız gerekir:

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

İletişim nesnesi kullanılabilir olduğunda veriler, Send* işlev ailesinden biri kullanılarak Sandboxee'ye gönderilebilir. comms API'nin örnek bir kullanımını crc4 örneğinde bulabilirsiniz. Aşağıdaki kod snippet'i bu örnekten bir alıntıyı göstermektedir. Yürütücü, SendBytes(buf, size) ile birlikte bir unsigned char buf[size] gönderir:

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

Sandboxee'den veri almak için Recv* işlevlerinden birini kullanın. Aşağıdaki kod snippet'i crc4 örneğinden bir alıntıdır. Yürütücü, sağlama toplamını 32 bitlik imzasız bir tam sayı olarak alır: uint32_t crc4;

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

Verileri Arabelleklerle Paylaşma

Bir diğer veri paylaşım işlevi de büyük miktarda veri paylaşmak ve yönetici ile Sandboxee arasında gidip gelen pahalı kopyaları önlemek için buffer API'yi kullanmaktır.

Yürütücü, boyuta ve aktarılacak verilere göre veya doğrudan dosya açıklayıcıdan bir Arabellek oluşturur ve yürütücüde comms->SendFD(), Sandboxee'de ise comms->RecvFD() kullanarak bunu Sandboxee'ye iletir.

Aşağıdaki kod snippet'inde yürütme aracının yan tarafını görebilirsiniz. Korumalı alan eşzamansız olarak çalışır ve bir arabellek aracılığıyla Korumalı Alan ile veri paylaşır:

// 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());

Korumalı alan tarafında ayrıca bir arabellek nesnesi oluşturmanız ve yürütücü tarafından gönderilen dosya açıklayıcıdaki verileri okumanız gerekir:

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