1. Sandbox-Executor-Methode auswählen
Das Sandboxing beginnt mit einem Executor (siehe Sandbox Executor), der für die Ausführung des Sandboxee verantwortlich ist. Die Headerdatei executor.h enthält die für diesen Zweck erforderliche API. Die API ist sehr flexibel und lässt Sie wählen, was für Ihren Anwendungsfall am besten geeignet ist. In den folgenden Abschnitten werden die drei Methoden beschrieben, aus denen Sie wählen können.
Methode 1: Eigenständig – Binärprogramm mit aktiviertem Sandboxing ausführen
Dies ist die einfachste Möglichkeit, die Sandbox zu nutzen. Sie wird empfohlen, wenn Sie eine gesamte Binärdatei in einer Sandbox ausführen möchten, für die Sie keinen Quellcode haben. Es ist auch die sicherste Methode, die Sandbox-Technologie zu verwenden, da es keine Initialisierung ohne Sandbox gibt, die nachteilige Auswirkungen haben könnte.
Im folgenden Code-Snippet definieren wir den Pfad der Binärdatei, die in einer Sandbox ausgeführt werden soll, und die Argumente, die an einen ausführbaren Systemaufruf übergeben werden müssen. Wie Sie in der Header-Datei executor.h sehen können, geben wir keinen Wert für envp
an und kopieren daher die Umgebung aus dem übergeordneten Prozess. Denken Sie daran, dass das erste Argument immer der Name des auszuführenden Programms ist und unser Snippet kein anderes Argument definiert.
Beispiele für diese Executor-Methode sind: static und 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);
Methode 2: Sandbox2 Forkserver – Teilen Sie dem Executor mit, wann in einer Sandbox ausgeführt werden soll.
Diese Methode bietet die Flexibilität, während der Initialisierung aus der Sandbox zu kommen und dann durch Aufrufen von ::sandbox2::Client::SandboxMeHere()
auszuwählen, wann die Sandbox in Betrieb genommen wird. Sie müssen in der Lage sein, im Code zu definieren, wann Sie mit dem Sandboxing beginnen möchten, und es muss sich um einen Single-Thread-Vorgang handeln. Weitere Informationen finden Sie in den FAQs.
Im folgenden Code-Snippet verwenden wir denselben Code wie oben unter Methode 1 beschrieben. Damit das Programm während der Initialisierung jedoch ohne Sandbox ausgeführt werden kann, rufen wir set_enable_sandbox_before_exec(false)
auf.
#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);
Da der Executor jetzt eine Sandbox deaktiviert hat, bis er vom Sandboxee benachrichtigt wird, müssen wir eine ::sandbox2::Client
-Instanz erstellen, die Kommunikation zwischen dem Executor und dem Sandboxee einrichten und dann den Executor benachrichtigen, dass unsere Initialisierung abgeschlossen ist und wir jetzt durch Aufrufen von sandbox2_client.SandboxMeHere()
mit dem Sandboxing beginnen möchten.
// 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();
…
Ein Beispiel für diese Executor-Methode ist crc4. Dabei ist crc4bin.cc
der Sandboxee und benachrichtigt den Executor (crc4sandbox.cc
), wann er in die Sandbox gelangen soll.
Methode 3: Benutzerdefinierter Forkserver – Binärprogramm vorbereiten, auf Fork-Anfragen warten und eigenständig in einer Sandbox ausführen
In diesem Modus können Sie ein Binärprogramm starten, für das Sandboxing vorbereiten und an einem bestimmten Zeitpunkt im Lebenszyklus Ihres Binärprogramms für den Executor verfügbar machen.
Der Executor sendet eine Fork-Anfrage an Ihre Binärdatei, die fork()
(über ::sandbox2::ForkingClient::WaitAndFork()
). Der neu erstellte Prozess kann mit ::sandbox2::Client::SandboxMeHere()
in einer Sandbox ausgeführt werden.
#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());
Beachten Sie, dass dieser Modus ziemlich kompliziert ist und nur in wenigen bestimmten Fällen anwendbar ist, z. B. bei geringen Arbeitsspeicheranforderungen. Du profitierst von COW, hast aber den Nachteil, dass es keine echte ASLR gibt. Ein weiteres typisches Anwendungsbeispiel wäre, wenn der Sandboxee eine lange, CPU-intensive Initialisierung hat, die ausgeführt werden kann, bevor die nicht vertrauenswürdigen Daten verarbeitet werden.
Ein Beispiel für diese Executor-Methode finden Sie unter custom_fork.