1. Choisir une méthode d'exécution du bac à sable

La mise en bac à sable commence par un exécutant (voir Sandbox Executor), qui est responsable de l'exécution du Sandboxee. Le fichier d'en-tête executor.h contient l'API nécessaire à cet effet. L'API est très flexible et vous permet de choisir ce qui convient le mieux à votre cas d'utilisation. Les sections suivantes décrivent les trois méthodes différentes que vous pouvez choisir.

Méthode 1 : Autonome – Exécuter un binaire avec le bac à sable déjà activé

Il s'agit de la méthode la plus simple pour utiliser le bac à sable. Elle est recommandée lorsque vous souhaitez mettre en bac à sable un binaire entier dont vous ne possédez pas le code source. C'est également le moyen le plus sûr d'utiliser le bac à sable, car il n'y a pas d'initialisation non sandboxée qui pourrait avoir des effets indésirables.

Dans l'extrait de code suivant, nous définissons le chemin d'accès au binaire à mettre en bac à sable et les arguments que nous devons transmettre à un appel système execve. Comme vous pouvez le voir dans le fichier d'en-tête executor.h, nous ne spécifions pas de valeur pour envp et copions donc l'environnement à partir du processus parent. N'oubliez pas que le premier argument est toujours le nom du programme à exécuter, et que notre extrait ne définit aucun autre argument.

Voici des exemples de cette méthode d'exécution : static et tool.

#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);

Méthode 2 : Forkserver Sandbox2 – Indiquer à l'exécuteur quand il doit être mis en bac à sable

Cette méthode offre la possibilité de ne pas être mise en bac à sable lors de l'initialisation, puis de choisir quand entrer dans le bac à sable en appelant ::sandbox2::Client::SandboxMeHere(). Vous devez être en mesure de définir dans le code quand vous souhaitez commencer à utiliser le bac à sable, et il doit être monothread (consultez les questions fréquentes pour en savoir plus).

Dans l'extrait de code suivant, nous utilisons le même code que celui décrit dans la méthode 1 ci-dessus. Toutefois, pour permettre au programme de s'exécuter de manière non sandboxée lors de l'initialisation, nous appelons 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);

L'exécuteur disposant désormais d'un bac à sable désactivé jusqu'à ce qu'il soit averti par le Sandboxee, nous devons créer une instance ::sandbox2::Client, configurer la communication entre l'exécuteur et le Sandboxee, puis informer l'exécuteur que notre initialisation est terminée et que nous souhaitons commencer le sandboxing en appelant 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();
  

crc4 est un exemple de cette méthode d'exécution, où crc4bin.cc est le Sandboxee et avertit l'exécuteur (crc4sandbox.cc) lorsqu'il doit entrer dans le bac à sable.

Méthode 3 : Forkserver personnalisé – Préparez un binaire, attendez les demandes de fork et mettez en bac à sable vous-même

Ce mode vous permet de démarrer un binaire, de le préparer pour le bac à sable et, à un moment précis du cycle de vie de votre binaire, de le mettre à la disposition de l'exécuteur.

L'exécuteur envoie une requête de fork à votre binaire, qui fork() (via ::sandbox2::ForkingClient::WaitAndFork()). Le processus nouvellement créé est prêt à être mis en bac à sable avec ::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());

N'oubliez pas que ce mode est assez compliqué et ne s'applique que dans quelques cas spécifiques, par exemple lorsque vous avez des exigences de mémoire strictes. Vous bénéficierez de COW, mais vous aurez l'inconvénient de ne pas disposer d'ASLR. Un autre exemple d'utilisation typique serait lorsque le Sandboxee a une longue initialisation gourmande en ressources processeur qui peut être exécutée avant le traitement des données non fiables.

Pour obtenir un exemple de cette méthode d'exécution, consultez custom_fork.