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