1. Scegli un metodo di esecutore sandbox

La limitazione tramite sandbox inizia con un esecutore (vedi Esecutore sandbox), che è responsabile dell'esecuzione di Sandboxee. Il file di intestazione executor.h contiene l'API necessaria a questo scopo. L'API è molto flessibile e ti consente di scegliere cosa funziona meglio per il tuo caso d'uso. Le seguenti sezioni descrivono i 3 diversi metodi tra cui puoi scegliere.

Metodo 1: autonomo: esegui un programma binario con il sandboxing già abilitato

Questo è il modo più semplice per utilizzare il sandboxing ed è quello consigliato quando vuoi eseguire la sandbox di un intero programma binario per il quale non disponi di codice sorgente. È inoltre il modo più sicuro per utilizzare il sandboxing, poiché non esiste un'inizializzazione senza sandbox che potrebbe avere effetti negativi.

Nello snippet di codice riportato di seguito, definiamo il percorso del programma binario da limitare con la sandbox e gli argomenti da passare a una chiamata di sistema execve. Come puoi vedere nel file di intestazione executor.h, non specifichiamo un valore per envp e quindi copiamo l'ambiente dal processo principale. Ricorda che il primo argomento è sempre il nome del programma da eseguire e il nostro snippet non definisce nessun altro argomento.

Esempi di questo metodo esecutore sono: statico e strumento.

#include "sandboxed_api/sandbox2/executor.h"

std::string path = "path/to/binary";
std::vector<std::string> args = {path};  // args[0] will become the sandboxed
                                         // process' argv[0], typically the
                                         // path to the binary.
auto executor = absl::make_unique<sandbox2::Executor>(path, args);

Metodo 2: forkserver Sandbox2 - Indica all'esecutore quando deve essere eseguito il sandboxing

Questo metodo offre la flessibilità di disattivare la sandbox durante l'inizializzazione, per poi scegliere quando avviare la limitazione tramite sandbox chiamando ::sandbox2::Client::SandboxMeHere(). Richiede la possibilità di definire nel codice quando vuoi avviare il sandboxing, oltre a essere a thread unico (leggi i motivi nelle Domande frequenti).

Nello snippet di codice riportato di seguito, utilizziamo lo stesso codice descritto nel precedente Metodo 1. Tuttavia, per consentire l'esecuzione del programma senza sandbox durante l'inizializzazione, chiamiamo set_enable_sandbox_before_exec(false).

#include "sandboxed_api/sandbox2/executor.h"

std::string path = "path/to/binary";
std::vector<std::string> args = {path};
auto executor = absl::make_unique<sandbox2::Executor>(path, args);
executor->set_enable_sandbox_before_exec(false);

Poiché ora l'esecutore ha una sandbox disabilitata fino a quando non viene inviata una notifica da Sandboxee, dobbiamo creare un'istanza ::sandbox2::Client, configurare la comunicazione tra l'esecutore e Sandboxee e poi informare l'esecutore che l'inizializzazione è terminata e vogliamo iniziare subito il sandboxing chiamando sandbox2_client.SandboxMeHere().

// main() of sandboxee
int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags(&argc, &argv, false);

  // Set-up the sandbox2::Client object, using a file descriptor (1023).
  sandbox2::Comms comms(sandbox2::Comms::kSandbox2ClientCommsFD);
  sandbox2::Client sandbox2_client(&comms);
  // Enable sandboxing from here.
  sandbox2_client.SandboxMeHere();
  …

Un esempio di questo metodo esecutore è crc4, dove crc4bin.cc è il Sandboxee e avvisa l'esecutore (crc4sandbox.cc) quando deve entrare nella sandbox.

Metodo 3: forkserver personalizzato - Prepara un programma binario, attendi le richieste di fork e sandbox in autonomia

Questa modalità ti consente di avviare un programma binario, prepararlo per il sandboxing e, in un momento specifico del ciclo di vita del programma binario, renderlo disponibile per l'esecutore.

L'esecutore invierà una richiesta di fork al tuo programma binario, che verrà fork() (tramite ::sandbox2::ForkingClient::WaitAndFork()). Il processo appena creato sarà pronto per essere limitato tramite sandbox con ::sandbox2::Client::SandboxMeHere().

#include "sandboxed_api/sandbox2/executor.h"

// Start the custom ForkServer
std::string path = "path/to/binary";
std::vector<std::string> args = {path};
auto fork_executor = absl::make_unique<sandbox2::Executor>(path, args);
fork_executor->StartForkServer();

// Initialize Executor with Comms channel to the ForkServer
auto executor = absl::make_unique<sandbox2::Executor>(
    fork_executor->ipc()->GetComms());

Tieni presente che questa modalità è piuttosto complicata e può essere applicata solo in alcuni casi specifici, ad esempio quando la memoria è richiesta. Trarrai beneficio da COW, ma hai il lato negativo del fatto che non esiste un'ASLR reale. Un altro esempio di utilizzo tipico è quando Sandboxee ha un'inizializzazione lunga e ad alta intensità di CPU che può essere eseguita prima che i dati non attendibili vengano elaborati.

Per un esempio di questo metodo esecutore, consulta custom_fork.