5. Общение с песочницей

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

Однако вам, скорее всего, понадобится более сложная логика связи между исполнителем и Sandboxee. API связи (см. заголовочный файл comms.h ) можно использовать для отправки целых чисел, строк, байтовых буферов, protobufs или файловых дескрипторов.

Совместное использование файловых дескрипторов

Используя API межпроцессного взаимодействия (см. ipc.h ), вы можете использовать MapFd() или ReceiveFd() :

  • Используйте MapFd() для сопоставления файловых дескрипторов от исполнителя с Sandboxee. Это можно использовать для обмена файлом, открытым из исполнителя, для использования в Sandboxee. Пример использования можно увидеть в static .

    // The executor opened /proc/version and passes it to the sandboxee as stdin
    executor->ipc()->MapFd(proc_version_fd, STDIN_FILENO);
    
  • Используйте ReceiveFd() для создания конечной точки пары сокетов. Это можно использовать для чтения стандартного вывода Sandboxee или стандартных ошибок. Пример использования можно увидеть в инструменте .

    // The executor receives a file descriptor of the sandboxee stdout
    int recv_fd1 = executor->ipc())->ReceiveFd(STDOUT_FILENO);
    

Использование API связи

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

Чтобы начать работу с API связи, вам сначала нужно получить объект связи из объекта Sandbox2:

sandbox2::Comms* comms = s2.comms();

Как только объект связи станет доступен, данные можно будет отправить в Sandboxee с помощью одной из функций семейства Send*. Вы можете найти пример использования API связи в примере crc4 . В приведенном ниже фрагменте кода показан отрывок из этого примера. Исполнитель отправляет unsigned char buf[size] с помощью SendBytes(buf, size) :

if (!(comms->SendBytes(static_cast<const uint8_t*>(buf), sz))) {
  /* handle error */
}

Чтобы получить данные от Sandboxee, используйте одну из функций Recv* . Фрагмент кода ниже представляет собой отрывок из примера crc4 . Исполнитель получает контрольную сумму в виде 32-битного целого числа без знака: uint32_t crc4;

if (!(comms->RecvUint32(&crc4))) {
  /* handle error */
}

Совместное использование данных с помощью буферов

Другая функция совместного использования данных — использование буферного API для совместного использования больших объемов данных и предотвращения дорогостоящих копий, которые пересылаются туда и обратно между исполнителем и Sandboxee.

Исполнитель создает буфер либо по размеру и передаваемым данным, либо непосредственно из файлового дескриптора, и передает его в песочницу, используя comms->SendFD() в исполнителе и comms->RecvFD() в песочнице.

В приведенном ниже фрагменте кода вы можете увидеть сторону исполнителя. Песочница работает асинхронно и обменивается данными через буфер с Sandboxee:

// start the sandbox asynchronously
s2.RunAsync();

// instantiate the comms object
sandbox2::Comms* comms = s2.comms();

// random buffer data we want to send
constexpr unsigned char buffer_data[] = /* random data */;
constexpr unsigned int buffer_dataLen = 34;

// create sandbox2 buffer
absl::StatusOr<std::unique_ptr<sandbox2::Buffer>> buffer =
     sandbox2::Buffer::CreateWithSize(1ULL << 20 /* 1Mib */);
std::unique_ptr<sandbox2::Buffer> buffer_ptr = std::move(buffer).value();

// point to the sandbox2 buffer and fill with data
uint8_t* buf = buffer_ptr‑>data();
memcpy(buf, buffer_data, buffer_data_len);

// send the data to the sandboxee
comms‑>SendFd(buffer_ptr‑>fd());

На стороне Sandboxee вам также необходимо создать объект буфера и прочитать данные из файлового дескриптора, отправленного исполнителем:

// establish the communication with the executor
int fd;
comms.RecvFD(&fd);

// create the buffer
absl::StatusOr<std::unique_ptr<sandbox2::Buffer>> buffer =
     sandbox2::Buffer::createFromFd(fd);

// get the data
auto buffer_ptr = std::move(buffer).value();
uint8_t* buf = buffer_ptr‑>data();

/* work with the buf object */
,

5. Общение с песочницей

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

Однако вам, скорее всего, понадобится более сложная логика связи между исполнителем и Sandboxee. API связи (см. заголовочный файл comms.h ) можно использовать для отправки целых чисел, строк, байтовых буферов, protobufs или файловых дескрипторов.

Совместное использование файловых дескрипторов

Используя API межпроцессного взаимодействия (см. ipc.h ), вы можете использовать MapFd() или ReceiveFd() :

  • Используйте MapFd() для сопоставления файловых дескрипторов от исполнителя с Sandboxee. Это можно использовать для обмена файлом, открытым из исполнителя, для использования в Sandboxee. Пример использования можно увидеть в static .

    // The executor opened /proc/version and passes it to the sandboxee as stdin
    executor->ipc()->MapFd(proc_version_fd, STDIN_FILENO);
    
  • Используйте ReceiveFd() для создания конечной точки пары сокетов. Это можно использовать для чтения стандартного вывода Sandboxee или стандартных ошибок. Пример использования можно увидеть в инструменте .

    // The executor receives a file descriptor of the sandboxee stdout
    int recv_fd1 = executor->ipc())->ReceiveFd(STDOUT_FILENO);
    

Использование API связи

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

Чтобы начать работу с API связи, вам сначала нужно получить объект связи из объекта Sandbox2:

sandbox2::Comms* comms = s2.comms();

Как только объект связи станет доступен, данные можно будет отправить в Sandboxee с помощью одной из функций семейства Send*. Вы можете найти пример использования API связи в примере crc4 . В приведенном ниже фрагменте кода показан отрывок из этого примера. Исполнитель отправляет unsigned char buf[size] с помощью SendBytes(buf, size) :

if (!(comms->SendBytes(static_cast<const uint8_t*>(buf), sz))) {
  /* handle error */
}

Чтобы получить данные от Sandboxee, используйте одну из функций Recv* . Фрагмент кода ниже представляет собой отрывок из примера crc4 . Исполнитель получает контрольную сумму в виде 32-битного целого числа без знака: uint32_t crc4;

if (!(comms->RecvUint32(&crc4))) {
  /* handle error */
}

Совместное использование данных с помощью буферов

Другая функция совместного использования данных — использование буферного API для совместного использования больших объемов данных и предотвращения дорогостоящих копий, которые пересылаются туда и обратно между исполнителем и Sandboxee.

Исполнитель создает буфер либо по размеру и передаваемым данным, либо непосредственно из файлового дескриптора, и передает его в песочницу, используя comms->SendFD() в исполнителе и comms->RecvFD() в песочнице.

В приведенном ниже фрагменте кода вы можете увидеть сторону исполнителя. Песочница работает асинхронно и обменивается данными через буфер с Sandboxee:

// start the sandbox asynchronously
s2.RunAsync();

// instantiate the comms object
sandbox2::Comms* comms = s2.comms();

// random buffer data we want to send
constexpr unsigned char buffer_data[] = /* random data */;
constexpr unsigned int buffer_dataLen = 34;

// create sandbox2 buffer
absl::StatusOr<std::unique_ptr<sandbox2::Buffer>> buffer =
     sandbox2::Buffer::CreateWithSize(1ULL << 20 /* 1Mib */);
std::unique_ptr<sandbox2::Buffer> buffer_ptr = std::move(buffer).value();

// point to the sandbox2 buffer and fill with data
uint8_t* buf = buffer_ptr‑>data();
memcpy(buf, buffer_data, buffer_data_len);

// send the data to the sandboxee
comms‑>SendFd(buffer_ptr‑>fd());

На стороне Sandboxee вам также необходимо создать объект буфера и прочитать данные из файлового дескриптора, отправленного исполнителем:

// establish the communication with the executor
int fd;
comms.RecvFD(&fd);

// create the buffer
absl::StatusOr<std::unique_ptr<sandbox2::Buffer>> buffer =
     sandbox2::Buffer::createFromFd(fd);

// get the data
auto buffer_ptr = std::move(buffer).value();
uint8_t* buf = buffer_ptr‑>data();

/* work with the buf object */