1. בחירת שיטה להרצת ארגז חול
ההרצה בארגז חול מתחילה עם רכיב Executor (ראו Sandbox Executor), שאחראי להרצת Sandboxee. קובץ הכותרת executor.h מכיל את ה-API שדרוש למטרה הזו. ה-API גמיש מאוד ומאפשר לכם לבחור את מה שהכי מתאים לתרחיש לדוגמה שלכם. בקטעים הבאים מתוארות 3 מתודולוגיות שונות שתוכלו לבחור מביניהן.
שיטה 1: עצמאי – הפעלת קובץ בינארי עם ארגז חול שכבר מופעל
זו הדרך הכי פשוטה להשתמש ב-Sandbox, והיא מומלצת כשרוצים להפעיל Sandbox על קובץ בינארי שלם שאין לו קוד מקור. זו גם הדרך הכי בטוחה להשתמש בארגז חול, כי אין אתחול מחוץ לארגז החול שיכול לגרום להשפעות שליליות.
בקטע הקוד הבא אנחנו מגדירים את הנתיב של הקובץ הבינארי שצריך להפעיל בסביבת ארגז חול, ואת הארגומנטים שצריך להעביר לקריאת המערכת execve. כפי שאפשר לראות בקובץ הכותרת 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);
מכיוון שה-executor (רכיב ההפעלה) נמצא עכשיו בארגז חול מושבת עד שהוא מקבל הודעה מה-Sandboxee (רכיב ארגז החול), אנחנו צריכים ליצור מופע של ::sandbox2::Client
, להגדיר תקשורת בין ה-executor ל-Sandboxee, ואז להודיע ל-executor שהאתחול שלנו הסתיים ואנחנו רוצים להתחיל להשתמש בארגז החול עכשיו על ידי קריאה ל-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();
…
דוגמה לשיטת executor היא crc4, שבה crc4bin.cc
הוא Sandboxee והוא מודיע ל-executor (crc4sandbox.cc
) מתי הוא צריך להיכנס לארגז החול.
שיטה 3: שרת פורקים בהתאמה אישית – מכינים קובץ בינארי, מחכים לבקשות פורק ומפעילים ארגז חול באופן עצמאי
במצב הזה אפשר להפעיל קובץ בינארי, להכין אותו להפעלת ארגז חול ובשלב מסוים במחזור החיים של הקובץ הבינארי, להפוך אותו לזמין למבצע.
התהליך יבצע בקשת פיצול לקובץ הבינארי שלכם, שתעבור דרך 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 אמיתי. דוגמה נוספת לשימוש אופייני היא כשב-Sandboxee יש אתחול ארוך שדורש הרבה משאבי CPU, שאפשר להריץ לפני עיבוד הנתונים הלא מהימנים.
דוגמה לשיטה הזו של מפעיל אפשר לראות ב-custom_fork.