1. Chọn một phương thức thực thi hộp cát

Quá trình tạo hộp cát bắt đầu bằng một trình thực thi (xem Sandbox Executor), 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 pháp mà bạn có thể lựa chọn.

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

Đây là cách đơn giản nhất để sử dụng hộp cát và là phương thức nên dùng khi bạn muốn đưa toàn bộ tệp nhị phân mà bạn không có mã nguồn vào hộp cát. Đâ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 tạo không có hộp cát nào có thể gây ra tác động xấu.

Trong đoạn mã sau, chúng ta xác định đường dẫn của tệp nhị phân cần được đưa vào hộp cát và các đối số mà chúng ta phải truyền đến một lệnh gọi hệ thống execve. 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 và do đó 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 sẽ được thực thi và đoạn mã của chúng ta không xác định bất kỳ đối số nào khác.

Ví dụ về phương thức thực thi này là: statictool.

#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 thức 2: Sandbox2 Forkserver – Cho biết thời điểm cần đưa trình thực thi vào hộp cát

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

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

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

Một 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 trình thực thi này sẽ nhập hộp cát.

Phương thức 3: Forkserver tuỳ chỉnh – Chuẩn bị một tệp nhị phân, đợi yêu cầu phân nhánh và tự tạo hộp cát

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

Trình thực thi sẽ gửi yêu cầu phâ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 đưa vào hộp cát bằng ::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());

Xin 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ụ: khi bạn có yêu cầu nghiêm ngặt về bộ nhớ. 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ụ khác về cách sử dụng điển hình là khi Sandboxee có một quá trình khởi tạo dài, tốn nhiều CPU có thể chạy trước khi dữ liệu không đáng tin cậy được xử lý.

Để biết ví dụ về phương thức thực thi này, hãy xem custom_fork.