1. Wybierz metodę wykonawcy piaskownicy

Tryb piaskownicy rozpoczyna się od wykonawcy (patrz Wykonawca piaskownicy), który odpowiada za uruchomienie narzędzia Sandboxee. Plik nagłówka executor.h zawiera interfejs API potrzebny do tego. Interfejs API jest bardzo elastyczny i umożliwia wybranie rozwiązania, które najlepiej sprawdzi się w Twoim przypadku. W sekcjach poniżej opisujemy 3 różne metody do wyboru.

Metoda 1. samodzielny – uruchom plik binarny z włączonym piaskownicą

Jest to najprostszy sposób korzystania z piaskownicy i zalecana, gdy chcesz umieścić w piaskownicy cały plik binarny, dla którego nie masz kodu źródłowego. Jest to również najbezpieczniejszy sposób korzystania z piaskownicy, ponieważ nie ma inicjowania poza piaskownicą, które mogłoby mieć negatywne skutki.

W tym fragmencie kodu definiujemy ścieżkę pliku binarnego umieszczonego w piaskownicy oraz argumenty, które należy przekazać do wywołania syscall w narzędziu execve. Jak widać w pliku nagłówka executor.h, nie określamy wartości envp, więc skopiujemy środowisko z procesu nadrzędnego. Pamiętaj, że pierwszy argument to zawsze nazwa programu, który ma zostać wykonany, a nasz fragment nie zawiera żadnego innego argumentu.

Przykłady tej metody wykonania to: static i 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);

Metoda 2. Serwer widłowy Sandbox2 – poinformuj wykonawcy, kiedy ma zostać włączony do piaskownicy

Ta metoda zapewnia elastyczność pozbawienia się piaskownicy podczas inicjowania, a następnie wybrania czasu przejścia do piaskownicy przez wywołanie metody ::sandbox2::Client::SandboxMeHere(). Wymaga to określenia w kodzie, kiedy chcesz rozpocząć piaskownicę, i musi być jednowątkowe (przyczyny tego procesu znajdziesz w Najczęstszych pytaniach).

W poniższym fragmencie kodu korzystamy z tego samego kodu, który został opisany powyżej w metodzie 1. Aby jednak umożliwić wykonywanie programu w trakcie inicjowania poza piaskownicą, wywołujemy funkcję 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);

Wykonawca ma teraz wyłączoną piaskownicę, dopóki nie otrzyma o niej powiadomienia. Dlatego musimy utworzyć instancję ::sandbox2::Client, skonfigurować komunikację między wykonawcą a osobą w trybie piaskownicy, a następnie powiadomić wykonawcy o zakończeniu inicjowania i teraz od razu rozpocząć piaskownicę, wywołując 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();
  …

Przykładem tej metody jest crc4, gdzie crc4bin.cc to użytkownik w środowisku piaskownicy, a wykonawca (crc4sandbox.cc) otrzymuje powiadomienie o konieczności przejścia do piaskownicy.

Metoda 3. Niestandardowy serwer widłowy – przygotuj plik binarny, poczekaj na żądania rozwidlenie i samodzielnie uruchom piaskownicę

Ten tryb umożliwia uruchomienie pliku binarnego, przygotowanie go do piaskownicy i udostępnienie go wykonawcy w określonym momencie cyklu życia pliku binarnego.

Wykonawca wyśle do pliku binarnego żądanie rozwidlenia w odpowiedzi na żądanie fork() (za pomocą ::sandbox2::ForkingClient::WaitAndFork()). Nowo utworzony proces będzie gotowy do umieszczenia w piaskownicy za pomocą funkcji ::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());

Pamiętaj, że ten tryb jest dość skomplikowany i można z niego korzystać tylko w nielicznych przypadkach, np. gdy masz zbyt mało pamięci. Korzyści przyniesie Ci korzyści, ale dodatkową wadą jest fakt, że w przypadku ASLR nie ma czegoś takiego. Innym przykładowym przykładem jest długie inicjowanie użytkownika piaskownicy, które inicjuje bardzo dużo procesora, zanim zostanie przetworzone niezaufane dane.

Przykład tej metody wykonawcy znajdziesz w sekcji custom_fork.