1. Chọn phương thức của trình thực thi Sandbox

Hộp cát bắt đầu bằng một trình thực thi (xem Trình thực thi hộp cát), trình thực thi này chịu trách nhiệm chạy Sandboxee. Tệp tiêu đề executor.h chứa API cần thiết cho mục đích này. API này rất linh hoạt và cho phép bạn chọn những gì phù hợp nhất với trường hợp sử dụng của mình. Các phần sau đây mô tả 3 phương thức mà bạn có thể chọn.

Phương pháp 1: Độc lập – Thực thi tệp nhị phân đã bật hộp cát

Đây là cách đơn giản nhất để sử dụng hộp cát và là phương pháp được đề xuất khi bạn muốn tạo hộp cát toàn bộ tệp nhị phân mà bạn không có mã nguồn. Đây cũng là cách an toàn nhất để sử dụng hộp cát, vì không có quá trình khởi chạy nào chưa được đặt trong hộp cát có thể gây ra tác động bất lợi.

Trong đoạn mã sau, chúng ta xác định đường dẫn của tệp nhị phân cần được tạo hộp cát và các đối số chúng ta phải truyền đến một lệnh gọi hệ thống thực thi. Như bạn có thể thấy trong tệp tiêu đề executor.h, chúng ta không chỉ định giá trị cho envp nên sẽ sao chép môi trường từ quy trình mẹ. Hãy nhớ rằng đối số đầu tiên luôn là tên của chương trình được thực thi và đoạn mã của chúng ta không định nghĩa bất kỳ đối số nào khác.

Ví dụ về phương thức thực thi này: tĩnhcông cụ.

#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);

Phương pháp 2: Sandbox2 Forkserver – Thông báo cho trình thực thi khi nào được tạo hộp cát

Phương thức này giúp bạn linh hoạt lựa chọn không hộp cát trong quá trình khởi chạy, sau đó chọn thời điểm chuyển sang hộp cát bằng cách gọi ::sandbox2::Client::SandboxMeHere(). Nó yêu cầu bạn phải có khả năng xác định trong mã khi bạn muốn bắt đầu hộp cát và nó phải là một luồng đơn (đọc lý do trong phần Câu hỏi thường gặp).

Trong đoạn mã sau, chúng tôi sử dụng cùng một mã như nêu trong Phương pháp 1 ở trên. Tuy nhiên, để cho phép chương trình thực thi theo cách không có hộp cát trong quá trình khởi chạy, chúng ta gọi 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);

Do trình thực thi này hiện có hộp cát bị tắt cho đến khi nhận được thông báo từ Sandboxee, nên chúng ta phải tạo một thực thể ::sandbox2::Client, thiết lập hoạt động giao tiếp giữa trình thực thi và Sandboxee, sau đó thông báo cho trình thực thi này rằng quá trình khởi chạy đã hoàn tất và chúng ta muốn bắt đầu tạo hộp cát ngay bây giờ bằng cách gọi 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();
  …

Ví dụ về phương thức thực thi này là crc4, trong đó crc4bin.cc là Sandboxee và thông báo cho trình thực thi (crc4sandbox.cc) khi cần truy cập vào hộp cát.

Phương pháp 3: Máy chủ Forkserver tuỳ chỉnh – Chuẩn bị tệp nhị phân, tự chờ các yêu cầu phát triển nhánh và hộp cát

Chế độ này cho phép bạn bắt đầu tệp nhị phân, chuẩn bị hộp cát cho hộp cát và cung cấp cho trình thực thi tại một thời điểm cụ thể trong vòng đời của tệp nhị phân.

Trình thực thi sẽ gửi yêu cầu phát triển nhánh đến tệp nhị phân của bạn, yêu cầu này sẽ fork() (thông qua ::sandbox2::ForkingClient::WaitAndFork()). Quy trình mới tạo sẽ sẵn sàng được đặt trong hộp cát với ::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());

Hãy lưu ý rằng chế độ này khá phức tạp và chỉ áp dụng trong một số trường hợp cụ thể, ví dụ như khi bạn có yêu cầu về bộ nhớ chặt chẽ. Bạn sẽ được hưởng lợi từ COW nhưng có nhược điểm là không có ASLR thực sự. Một ví dụ về cách sử dụng điển hình khác là khi Sandboxee có một quá trình khởi chạy dài, tốn nhiều CPU, có thể chạy trước khi xử lý dữ liệu không đáng tin cậy.

Để xem ví dụ về phương thức thực thi này, hãy tham khảo custom_fork.