1. เลือกวิธีดำเนินการของแซนด์บ็อกซ์

แซนด์บ็อกซ์จะเริ่มต้นด้วยผู้ดำเนินการ (ดูผู้ดำเนินการแซนด์บ็อกซ์) ซึ่งมีหน้าที่ในการเรียกใช้แซนด์บ็อกซ์ ไฟล์ส่วนหัว executor.h มี API ที่จำเป็นสำหรับวัตถุประสงค์นี้ API มีความยืดหยุ่นสูงและให้คุณเลือกได้ที่เหมาะกับกรณีการใช้งานของคุณมากที่สุด ส่วนต่อไปนี้จะอธิบายถึง 3 วิธีการที่คุณสามารถเลือกได้

วิธีที่ 1: สแตนด์อโลน – เรียกใช้ไบนารีที่เปิดใช้แซนด์บ็อกซ์อยู่แล้ว

นี่เป็นวิธีที่ง่ายที่สุดในการใช้แซนด์บ็อกซ์และเป็นวิธีการที่แนะนำเมื่อคุณต้องการแซนด์บ็อกซ์ทั้งไบนารีซึ่งคุณไม่มีซอร์สโค้ด และยังเป็นวิธีที่ปลอดภัยที่สุดในการใช้แซนด์บ็อกซ์ เนื่องจากไม่มีการเริ่มต้นนอกแซนด์บ็อกซ์ที่อาจส่งผลเสีย

ในข้อมูลโค้ดต่อไปนี้ เรากำหนดเส้นทางของไบนารีที่จะทำการแซนด์บ็อกซ์และอาร์กิวเมนต์ที่เราต้องส่งผ่านไปยัง execve syscall ดังที่คุณเห็นในไฟล์ส่วนหัว 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() กำหนดให้คุณต้องระบุในโค้ดเมื่อต้องการเริ่มต้นแซนด์บ็อกซ์ และต้องเป็นชุดข้อความเดียว (อ่านเหตุผลในคำถามที่พบบ่อย)

ในข้อมูลโค้ดต่อไปนี้ เราใช้โค้ดเดียวกับที่ระบุไว้ในวิธีที่ 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: Custom Forkserver – เตรียมไบนารี รอคำขอ Fork และใช้แซนด์บ็อกซ์ด้วยตนเอง

โหมดนี้ช่วยให้คุณเริ่มต้นไบนารี เตรียมไบนารีสำหรับแซนด์บ็อกซ์ และทำให้ไฟล์พร้อมใช้งานสำหรับผู้ดำเนินการเมื่อถึงช่วงเวลาหนึ่งในวงจรของไบนารี

ตัวดำเนินการจะส่งคำขอ Fork ไปยังไบนารีของคุณ ซึ่งจะ fork() (ผ่าน ::sandbox2::ForkingClient::WaitAndFork()) กระบวนการที่สร้างขึ้นใหม่จะพร้อมสำหรับการแซนด์บ็อกซ์ด้วย ::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());

โปรดทราบว่าโหมดนี้ค่อนข้างซับซ้อนและใช้ได้เฉพาะในบางกรณีเท่านั้น เช่น เมื่อคุณมีความต้องการหน่วยความจำเต็ม คุณจะได้รับประโยชน์จาก COW แต่ข้อเสียก็คือไม่มี ASLR จริงๆ ตัวอย่างการใช้งานทั่วไปอีกตัวอย่างหนึ่งคือเมื่อแซนด์บ็อกซ์มีการเริ่มการทำงานของ CPU ที่ใช้เวลานานซึ่งเรียกใช้ได้ก่อนที่จะมีการประมวลผลข้อมูลที่ไม่น่าเชื่อถือ

ดูตัวอย่างเมธอดของผู้ดำเนินการนี้ได้ที่ custom_fork