5. Comunicação com o Sandboxee
Por padrão, o executor pode se comunicar com o Sandboxee usando descritores de arquivo. Isso pode ser tudo o que você precisa, por exemplo, se quiser apenas compartilhar um arquivo com o Sandboxee ou ler a saída padrão dele.
No entanto, é muito provável que você precise 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 bytes, protobufs ou descritores de arquivo.
Compartilhamento de descritores de arquivos
Usando a API de comunicação entre processos (consulte
ipc.h),
é possível usar MapFd()
ou ReceiveFd()
:
Use
MapFd()
para mapear descritores de arquivo do executor para o Sandboxee. Isso pode ser usado para compartilhar um arquivo aberto do executor para uso no Sandboxee. Um exemplo de uso pode ser visto em static.// 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 socketpair. Isso pode ser usado para ler a saída padrão ou os erros padrão do Sandboxee. Um exemplo de uso pode ser visto 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 comms conveniente. Essa é uma maneira simples e fácil de compartilhar números inteiros, strings ou buffers de bytes entre o executor e o Sandboxee. Confira abaixo alguns snippets de código que podem ser encontrados no exemplo crc4.
Para começar a usar a API Comms, primeiro você precisa extrair 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 ao Sandboxee usando uma
das funções da família Send*. Confira um exemplo de uso da API de comunicações
no exemplo 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 crc4. O executor recebe a soma de verificação em um número inteiro sem assinatura 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 buffer para compartilhar grandes quantidades de dados e evitar cópias caras que são enviadas entre o executor e o Sandboxee.
O executor cria um buffer, seja por tamanho e dados a serem transmitidos, ou diretamente
de um descritor de arquivo, e o transmite ao Sandboxee usando comms->SendFD()
no executor e comms->RecvFD()
no Sandboxee.
No snippet de código abaixo, você pode ver o lado do executor. O sandbox é executado de forma assíncrona e compartilha dados por 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, também é necessário 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 */