5. Общение с Sandboxee

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

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

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

Используя 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-интерфейсом Comms, сначала необходимо получить объект Comms из объекта Sandbox2:

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

После того, как объект comms станет доступен, данные можно отправить в Sandboxee с помощью одной из функций семейства Send*. Пример использования API comms можно найти в примере 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.

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

В приведённом ниже фрагменте кода вы видите сторону исполнителя. Песочница работает асинхронно и обменивается данными с 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 */