5. Comunicazione con il sandboxee
Per impostazione predefinita, l'esecutore può comunicare con Sandboxee tramite i descrittori di file. Potrebbe essere tutto ciò di cui hai bisogno, ad esempio se vuoi solo condividere un file con Sandboxee o leggere l'output standard di Sandboxee.
Tuttavia, molto probabilmente hai bisogno di una logica di comunicazione più complessa tra l'executor e Sandboxee. L'API comms (vedi il file di intestazione comms.h) può essere utilizzata per inviare numeri interi, stringhe, buffer di byte, protobuf o descrittori di file.
Condivisione dei descrittori di file
Utilizzando l'API Inter-Process Communication (vedi
ipc.h),
puoi utilizzare MapFd()
o ReceiveFd()
:
Utilizza
MapFd()
per mappare i descrittori di file dall'executor a Sandboxee. Può essere utilizzato per condividere un file aperto dall'executor per l'utilizzo nel Sandboxee. Un esempio di utilizzo è disponibile in static.// The executor opened /proc/version and passes it to the sandboxee as stdin executor->ipc()->MapFd(proc_version_fd, STDIN_FILENO);
Utilizza
ReceiveFd()
per creare un endpoint socketpair. Può essere utilizzato per leggere l'output standard o gli errori standard del sandboxee. Un esempio di utilizzo è visibile nello strumento.// The executor receives a file descriptor of the sandboxee stdout int recv_fd1 = executor->ipc())->ReceiveFd(STDOUT_FILENO);
Utilizzo dell'API comms
Sandbox2 fornisce una comoda API comms. Questo è un modo semplice e facile per condividere numeri interi, stringhe o buffer di byte tra l'executor e Sandboxee. Di seguito sono riportati alcuni snippet di codice che puoi trovare nell'esempio crc4.
Per iniziare a utilizzare l'API comms, devi prima ottenere l'oggetto comms dall'oggetto Sandbox2:
sandbox2::Comms* comms = s2.comms();
Una volta disponibile l'oggetto comms, i dati possono essere inviati a Sandboxee utilizzando una
delle funzioni della famiglia Send*. Puoi trovare un esempio di utilizzo dell'API comms
nell'esempio crc4. Lo snippet di codice
di seguito mostra un estratto di questo esempio. L'esecutore testamentario invia un unsigned char
buf[size]
con SendBytes(buf, size)
:
if (!(comms->SendBytes(static_cast<const uint8_t*>(buf), sz))) {
/* handle error */
}
Per ricevere dati dal sandboxee, utilizza una delle funzioni Recv*
. Lo snippet
di codice riportato di seguito è un estratto dell'esempio
crc4. L'esecutore riceve
il checksum in un numero intero senza segno a 32 bit: uint32_t crc4;
if (!(comms->RecvUint32(&crc4))) {
/* handle error */
}
Condividere dati con i buffer
Un'altra funzionalità di condivisione dei dati è l'utilizzo dell'API buffer per condividere grandi quantità di dati ed evitare costose copie inviate avanti e indietro tra l'executor e Sandboxee.
L'executor crea un buffer, in base alle dimensioni e ai dati da trasferire, oppure direttamente
da un descrittore di file e lo passa a Sandboxee utilizzando comms->SendFD()
nell'executor e comms->RecvFD()
in Sandboxee.
Nello snippet di codice riportato di seguito, puoi vedere il lato dell'esecutore. La sandbox viene eseguita in modo asincrono e condivide i dati tramite un buffer con 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());
Dal lato del sandboxee, devi anche creare un oggetto buffer e leggere i dati dal descrittore di file inviato dall'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 */