1. Выберите метод использования песочницы в качестве исполнителя.

Песочница начинается с исполнителя (см. Исполнитель песочницы ), который отвечает за запуск объекта, находящегося в песочнице . Заголовочный файл executor.h содержит API, необходимый для этой цели. API очень гибкий и позволяет выбрать тот, который лучше всего подходит для вашего случая. В следующих разделах описаны 3 различных метода, из которых вы можете выбрать.

Метод 1: Автономный режим – Запуск исполняемого файла с уже включенной песочницей.

Это самый простой способ использования песочницы и рекомендуемый метод, если вы хотите изолировать весь исполняемый файл, для которого у вас нет исходного кода. Это также самый безопасный способ использования песочницы, поскольку отсутствует инициализация вне песочницы, которая могла бы иметь негативные последствия.

В приведенном ниже фрагменте кода мы определяем путь к исполняемому файлу, который нужно изолировать, и аргументы, которые необходимо передать системному вызову execve. Как видно в заголовочном файле executor.h , мы не указываем значение для envp и, следовательно, копируем окружение из родительского процесса. Помните, что первый аргумент всегда является именем программы, которую нужно выполнить, и наш фрагмент кода не определяет никаких других аргументов.

Примерами такого метода исполнителя являются: static и 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);

Метод 2: Sandbox2 Forkserver – Укажите исполнителю, когда следует перейти в песочницу.

Этот метод обеспечивает гибкость, позволяя отключать песочницу на этапе инициализации и затем выбирать момент включения песочницы, вызывая ::sandbox2::Client::SandboxMeHere() . Для его использования необходимо иметь возможность определять в коде момент запуска песочницы, и он должен быть однопоточным (подробнее об этом в разделе FAQ ).

В приведенном ниже фрагменте кода мы используем тот же код, что и в Методе 1 выше. Однако, чтобы разрешить выполнение программы без использования песочницы во время инициализации, мы вызываем функцию 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);

Поскольку исполнитель теперь находится в отключенной песочнице до получения уведомления от принимающей стороны, нам необходимо создать экземпляр ::sandbox2::Client , установить связь между исполнителем и принимающей стороной, а затем уведомить исполнителя о завершении инициализации и желании возобновить работу в песочнице, вызвав метод 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 , где crc4bin.cc является объектом, находящимся в песочнице, и уведомляет исполнитель ( crc4sandbox.cc ) о необходимости войти в песочницу.

Метод 3: Собственный форк-сервер – подготовьте бинарный файл, дождитесь запросов на создание форка и создайте собственную песочницу.

Этот режим позволяет запустить исполняемый файл, подготовить его к работе в изолированной среде и, в определенный момент жизненного цикла исполняемого файла, сделать его доступным для исполнителя.

Исполнитель отправит запрос на создание дочернего процесса вашему исполняемому файлу, который выполнит операцию fork() (через ::sandbox2::ForkingClient::EnterForkLook() ). Вновь созданный процесс будет готов к изоляции с помощью ::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());

Следует помнить, что этот режим довольно сложен и применим лишь в нескольких конкретных случаях; например, когда у вас ограниченные требования к памяти. Вы получите преимущества от механизма «кто напишет — увидишь», но при этом будет недостаток в отсутствии реального механизма ASLR. Другой типичный пример использования — когда в Sandboxee выполняется длительная, ресурсоемкая инициализация, которая может быть запущена до обработки недоверенных данных.

Пример использования этого метода исполнителя см. в custom_fork .