5. Como se comunicar com o sandboxee
Por padrão, o executor pode se comunicar com o sandboxee usando descritores de arquivo. Isso pode ser tudo que você precisa, por exemplo, se quiser apenas compartilhar um arquivo com o sandboxee ou ler a saída padrão dele.
No entanto, você provavelmente vai precisar de uma lógica de comunicação mais complexa entre o executor e o sandboxee. A API comms (consulte o arquivo de cabeçalho comms.h) pode ser usada para enviar números inteiros, strings, buffers de byte, protobufs ou descritores de arquivos.
Como compartilhar descritores de arquivos
Com a API Inter-Process Communication (consulte ipc.h), é possível usar MapFd()
ou ReceiveFd()
:
Use
MapFd()
para mapear descritores de arquivos do executor para o sandboxee. Isso pode ser usado para compartilhar um arquivo aberto pelo executor para uso no Sandboxee. Um exemplo de uso pode ser visto em estático.// The executor opened /proc/version and passes it to the sandboxee as stdin executor->ipc()->MapFd(proc_version_fd, STDIN_FILENO);
Use
ReceiveFd()
para criar um endpoint de socketpair. Pode ser usado para ler a saída padrão ou os erros padrão do sandboxee. Veja um exemplo de uso na ferramenta.// The executor receives a file descriptor of the sandboxee stdout int recv_fd1 = executor->ipc())->ReceiveFd(STDOUT_FILENO);
Como usar a API comms
O Sandbox2 oferece uma API de comunicações conveniente. Essa é uma maneira simples e fácil de compartilhar números inteiros, strings ou buffers de byte entre o executor e o sandboxee. Confira abaixo alguns snippets de código que podem ser encontrados no exemplo do crc4.
Para começar a usar a API comms, primeiro você precisa obter o objeto comms do objeto Sandbox2:
sandbox2::Comms* comms = s2.comms();
Quando o objeto de comunicação estiver disponível, os dados poderão ser enviados para o Sandboxee usando uma da família de funções Enviar*. Confira um exemplo de uso da API comms no crc4. O snippet de código abaixo mostra um trecho desse exemplo. O executor envia um unsigned char buf[size]
com SendBytes(buf, size)
:
if (!(comms->SendBytes(static_cast<const uint8_t*>(buf), sz))) {
/* handle error */
}
Para receber dados do sandboxee, use uma das funções Recv*
. O snippet de código abaixo é um trecho do exemplo do crc4. O executor recebe a soma de verificação em um número inteiro não assinado de 32 bits:
uint32_t crc4;
if (!(comms->RecvUint32(&crc4))) {
/* handle error */
}
Compartilhamento de dados com buffers
Outra funcionalidade de compartilhamento de dados é usar a API de buffer para compartilhar grandes quantidades de dados e evitar cópias caras entre o executor e o sandboxee.
O executor cria um buffer, por tamanho e dados a serem transmitidos, ou diretamente de um descritor de arquivo, e o transmite para o sandboxee usando comms->SendFD()
no executor e comms->RecvFD()
no sandboxee.
No snippet de código abaixo, é possível observar o lado do executor. O sandbox é executado de maneira assíncrona e compartilha dados por meio de um buffer com o 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());
No lado do sandboxee, você também precisa criar um objeto de buffer e ler os dados do descritor de arquivo enviado pelo executor:
// 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 */