सैंडबॉक्स2 के साथ शुरू करें

इस पेज पर, Sandbox2 की मदद से खुद का सैंडबॉक्स एनवायरमेंट बनाने का तरीका बताया जाएगा. आप सैंडबॉक्स नीति को परिभाषित करने के तरीके के साथ-साथ कुछ बेहतर, लेकिन सामान्य ट्वीक के बारे में जानेंगे. हेडर फ़ाइलों में उदाहरण और कोड दस्तावेज़ के साथ, यहां दी गई जानकारी को गाइड के तौर पर इस्तेमाल करें.

1. सैंडबॉक्स एक्ज़ीक्यूट करने वाला तरीका चुनें

सैंडबॉक्सिंग की शुरुआत एक एक्ज़ीक्यूटर (Sandbox Executor देखें) से होती है, जो Sandboxee को चलाने के लिए ज़िम्मेदार है. executor.h हेडर फ़ाइल में इस काम के लिए ज़रूरी एपीआई शामिल होता है. इस एपीआई में बहुत ज़रूरत के हिसाब से बदलाव किए जा सकते हैं. इसकी मदद से, अपनी ज़रूरत के हिसाब से किसी सुविधा को चुना जा सकता है. यहां दिए गए सेक्शन में, तीन अलग-अलग तरीकों के बारे में बताया गया है. इनमें से किसी एक तरीके को चुना जा सकता है.

पहला तरीका: स्टैंड-अलोन – सैंडबॉक्सिंग की सुविधा पहले से चालू करके बाइनरी फ़ाइल का इस्तेमाल करें

यह सैंडबॉक्सिंग का इस्तेमाल करने का सबसे आसान तरीका है. यह तरीका तब सुझाया जाता है, जब आपको एक ऐसी पूरी बाइनरी को सैंडबॉक्स करना हो जिसके लिए आपके पास कोई सोर्स कोड नहीं है. यह सैंडबॉक्सिंग को इस्तेमाल करने का सबसे सुरक्षित तरीका भी है. ऐसा नहीं है, क्योंकि इसमें सैंडबॉक्स न की गई प्रोसेस को शुरू करने की कोई ज़रूरत नहीं है. इसकी वजह से खराब असर पड़ सकता है.

नीचे दिए गए कोड स्निपेट में, हम सैंडबॉक्स किए जाने वाले बाइनरी के पाथ को तय करते हैं. साथ ही, execve syscall को पास किए जाने वाले तर्क भी तय करते हैं. जैसा कि executor.h हेडर फ़ाइल में देखा जा सकता है, हम envp के लिए कोई वैल्यू तय नहीं करते हैं. इसलिए, पैरंट प्रोसेस से एनवायरमेंट को कॉपी किया जाता है. याद रखें कि पहला आर्ग्युमेंट, एक्ज़ीक्यूट किए जाने वाले प्रोग्राम का नाम होता है. साथ ही, हमारा स्निपेट कोई दूसरा आर्ग्युमेंट तय नहीं करता.

एक्सपोर्ट करने वाले इस तरीके के उदाहरण: स्टैटिक और टूल हैं.

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

दूसरा तरीका: Sandbox2 फ़ोर्कसर्वर – एक्सक्यूटर को बताएं कि सैंडबॉक्स कब करना है

इस तरीके से, शुरू करने के दौरान सैंडबॉक्स न किए जाने की सुविधा मिलती है. इसके बाद, ::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);

फ़िलहाल, एक्ज़ीक्यूटर में एक बंद सैंडबॉक्स है, जिसे Sandboxee से सूचना मिलने तक बंद किया जाता है. इसलिए, हमें ::sandbox2::Client इंस्टेंस बनाना होगा और एक्ज़िक्यूटर और Sandboxee के बीच कम्यूनिकेशन सेट अप करना होगा. इसके बाद, एक्ज़ीक्यूटर को यह सूचना देनी होगी कि हमारा इनिशिएटिवेशन पूरा हो गया है और हमें 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) को इसकी सूचना देता है कि उसे सैंडबॉक्स में कब जाना चाहिए.

तीसरा तरीका: कस्टम फ़ोर्कसर्वर – एक बाइनरी तैयार करें, फ़ोर्क अनुरोधों का इंतज़ार करें, और खुद सैंडबॉक्स करें

यह मोड आपको बाइनरी शुरू करने देता है, उसे सैंडबॉक्सिंग के लिए तैयार करने देता है, और, अपनी बाइनरी के लाइफ़साइकल के किसी खास समय पर, उसे एक्ज़ीक्यूटर के लिए उपलब्ध कराने देता है.

एक्ज़ीक्यूटर, आपकी बाइनरी को फ़ोर्क अनुरोध भेजेगा, जिसमें 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 से फ़ायदा होगा, लेकिन इसका एक नुकसान यह भी है कि असली एएसएलआर नहीं होता है. इसके इस्तेमाल का एक अन्य उदाहरण यह है कि जब Sandboxee में लंबे समय तक सीपीयू की ज़रूरत के हिसाब से प्रोसेस शुरू किया जाता है, तब गैर-भरोसेमंद डेटा प्रोसेस होने से पहले उसे चलाया जा सकता है.

एक्सपोर्ट करने वाले इस तरीके के उदाहरण के लिए, custom_fork देखें.

2. एक सैंडबॉक्स नीति बनाएं

एक एक्सक्यूटर मिलने के बाद, हो सकता है कि आप सैंडबॉक्स के लिए एक सैंडबॉक्स नीति तय करना चाहें. ऐसा न होने पर, सैंडबॉक्स को सिर्फ़ डिफ़ॉल्ट सिस्कॉल नीति से सुरक्षित किया जाता है.

सैंडबॉक्स नीति का मकसद, उन सिस्टम कॉल और तर्कों को सीमित करना है जिन्हें सैंडबॉक्स बना सकता है. साथ ही, उन फ़ाइलों को भी सीमित करना है जिन्हें वह ऐक्सेस कर सकता है. आपको जिस कोड को सैंडबॉक्स करना है उसके लिए ज़रूरी सिस्टम कॉल की पूरी जानकारी होनी चाहिए. syscalls को देखने का एक तरीका यह है कि कोड को Linux के कमांड-लाइन टूल स्ट्रेस की मदद से चलाया जाए.

सिस्टम कॉल की सूची मिलने के बाद, नीति तय करने के लिए PolicyBuilder का इस्तेमाल किया जा सकता है. PolicyBuilder में कई आसान और हेल्पर फ़ंक्शन शामिल होते हैं. इनकी मदद से, कई तरह के काम किए जा सकते हैं. यहां दी गई सूची, उपलब्ध फ़ंक्शन का सिर्फ़ एक छोटा-सा हिस्सा है:

  • प्रोसेस शुरू होने के लिए, किसी भी सिस्टम को अनुमति वाली सूची में जोड़ें:
    • AllowStaticStartup();
    • AllowDynamicStartup();
  • किसी भी ओपन /read/write* syscalls को अनुमति वाली सूची में डालें:
    • AllowOpen();
    • AllowRead();
    • AllowWrite();
  • किसी भी एग्ज़िट/ऐक्सेस/राज्य से जुड़े सिस्टम कॉल को अनुमति वाली सूची में जोड़ें:
    • AllowExit();
    • AllowStat();
    • AllowAccess();
  • नींद या समय से जुड़े सिस्टम के इस्तेमाल को अनुमति दें:
    • AllowTime();
    • AllowSleep();

ये सुविधा फ़ंक्शन, किसी भी काम के सिस्टम को अनुमति वाली सूची में शामिल करते हैं. इसका फ़ायदा यह है कि एक जैसी नीति का इस्तेमाल उन अलग-अलग आर्किटेक्चर पर किया जा सकता है जहां कुछ खास सिस्टम (जैसे, ARM64 में कोई ओपन सिस्ट कॉल नहीं है) उपलब्ध नहीं हैं. हालांकि, इससे सुरक्षा के लिहाज़ से ज़्यादा सुरक्षा जोखिम होने की संभावना कम हो जाती है. उदाहरण के लिए,AllowOpen() की मदद से, Sandboxee को किसी भी ओपन से जुड़े syscall को कॉल करने में मदद मिलती है. अगर आपको सिर्फ़ एक सिस्टम को अनुमति देनी है, तो AllowSyscalls() का इस्तेमाल करें. इसके लिए, एक बार में एक से ज़्यादा सिस्टम कॉल की अनुमति देने के लिए, AllowSyscall(); का इस्तेमाल करें.

अभी तक नीति सिर्फ़ syscall आइडेंटिफ़ायर की जांच करती है. अगर नीति को और मज़बूत बनाना है और ऐसी नीति तय करना है जिसमें सिर्फ़ कुछ खास तर्कों के साथ सिस्कॉल की अनुमति है, तो आपको AddPolicyOnSyscall() या AddPolicyOnSyscalls() का इस्तेमाल करना होगा. ये फ़ंक्शन न सिर्फ़ syscall आईडी को एक तर्क के रूप में लेते हैं, बल्कि Linux कर्नेल से bpf हेल्पर मैक्रो का इस्तेमाल करके एक रॉ secCom-bpf फ़िल्टर भी इस्तेमाल करते हैं. BPF के बारे में ज़्यादा जानकारी के लिए kernel दस्तावेज़ देखें. अगर आपको बार-बार एक ही तरह के बीपीएफ़ कोड लिखने की ज़रूरत है और आपके हिसाब से इसमें उपयोगिता का रैपर होना चाहिए, तो सुविधा के लिए अनुरोध करें.

syscall से जुड़े फ़ंक्शन के अलावा, PolicyBuilder किसी फ़ाइल/डायरेक्ट्री को सैंडबॉक्स में बाइंड करने के लिए, फ़ाइल सिस्टम से जुड़े कई फ़ंक्शन भी उपलब्ध कराता है. जैसे, AddFile() या AddDirectory(). सैंडबॉक्स में फ़ाइल के लिए अस्थायी स्टोरेज जोड़ने के लिए, AddTmpfs() हेल्पर का इस्तेमाल किया जा सकता है.

AddLibrariesForBinary() खास तौर पर काम का फ़ंक्शन है. यह बाइनरी के लिए ज़रूरी लाइब्रेरी और लिंकर जोड़ता है.

माफ़ करें, सिस्टम को अनुमति वाली सूची में शामिल करने का काम, अब भी मैन्युअल तरीके से करना होगा. उन syscalls की मदद से नीति बनाएं जिनके बारे में आपको पता है कि आपकी बाइनरी ज़रूरतें क्या हैं. साथ ही, उन्हें एक सामान्य वर्कलोड के साथ चलाएं. अगर किसी नीति का उल्लंघन होता है, तो सिस्कॉल को अनुमति दें और इस प्रोसेस को दोहराएं. अगर आपको लगता है कि किसी नीति का उल्लंघन हुआ है और आपको लगता है कि वह अनुमति वाली सूची में शामिल होना जोखिम भरा हो सकता है और प्रोग्राम गड़बड़ियों को सही तरीके से हैंडल करता है, तो BlockSyscallWithErrno() की मदद से गड़बड़ी का मैसेज दिखाया जा सकता है.

#include "sandboxed_api/sandbox2/policy.h"
#include "sandboxed_api/sandbox2/policybuilder.h"
#include "sandboxed_api/sandbox2/util/bpf_helper.h"

std::unique_ptr<sandbox2::Policy> CreatePolicy() {
  return sandbox2::PolicyBuilder()
    .AllowSyscall(__NR_read)  // See also AllowRead()
    .AllowTime()              // Allow time, gettimeofday and clock_gettime
    .AddPolicyOnSyscall(__NR_write, {
        ARG(0),        // fd is the first argument of write (argument #0)
        JEQ(1, ALLOW), // allow write only on fd 1
        KILL,          // kill if not fd 1
    })
    .AddPolicyOnSyscall(__NR_mprotect, {
        ARG_32(2), // prot is a 32-bit wide argument, so it's OK to use *_32
                   // macro here
        JNE32(PROT_READ | PROT_WRITE, KILL), // prot must be the RW, otherwise
                                             // kill the process
        ARG(1), // len is a 64-bit argument
        JNE(0x1000, KILL),  // Allow single page syscalls only, otherwise kill
                            // the process
        ALLOW,              // Allow for the syscall to proceed, if prot and
                            // size match
    })
    // Allow the openat() syscall but always return "not found".
    .BlockSyscallWithErrno(__NR_openat, ENOENT)
    .BuildOrDie();
}

3. सीमाएं अडजस्ट करें

सैंडबॉक्स नीति, सैंडबॉक्स को खास सिस्टम कॉल करने से रोकती है. इस तरह, वह हमले की सरफ़ेस को कम करती है. हालांकि, कोई हमलावर किसी प्रोसेस को हमेशा के लिए चलाकर, अनचाहे असर डाल सकता है. इसके अलावा, वह रैम और अन्य संसाधनों को खत्म कर सकता है.

इस जोखिम का समाधान करने के लिए, Sandboxee डिफ़ॉल्ट रूप से सख्त निष्पादन सीमाओं के तहत काम करता है. अगर इन डिफ़ॉल्ट सीमाओं की वजह से आपके प्रोग्राम को सही तरीके से पूरा करने में समस्याएं आती हैं, तो आपके पास sandbox2::Limits क्लास का इस्तेमाल करके, एक्सक्यूटर ऑब्जेक्ट पर limits() को कॉल करके इनमें बदलाव करने का विकल्प होता है.

नीचे दिया गया कोड स्निपेट, सीमा को घटाने या बढ़ाने के कुछ उदाहरण दिखाता है. सभी उपलब्ध विकल्पों को limits.h हेडर फ़ाइल में शामिल किया गया है.

// Restrict the address space size of the sandboxee to 4 GiB.
executor->limits()->set_rlimit_as(4ULL << 30);
// Kill sandboxee with SIGXFSZ if it writes more than 1 GiB to the filesystem.
executor->limits()->set_rlimit_fsize(1ULL << 30);
// Number of file descriptors which can be used by the sandboxee.
executor->limits()->set_rlimit_nofile(1ULL << 10);
// The sandboxee is not allowed to create core files.
executor->limits()->set_rlimit_core(0);
// Maximum 300s of real CPU time.
executor->limits()->set_rlimit_cpu(300);
// Maximum 120s of wall time.
executor->limits()->set_walltime_limit(absl::Seconds(120));

sandbox2::Limits क्लास के इस्तेमाल के उदाहरण के लिए, टूल का उदाहरण देखें.

4. सैंडबॉक्स चलाएं

पिछले सेक्शन में, आपने सैंडबॉक्स किया गया एनवायरमेंट, नीति, एक्ज़ीक्यूटर, और Sandboxee तैयार किया है. अगले चरण में, Sandbox2 ऑब्जेक्ट बनाना और उसे चलाना है.

सिंक्रोनस रूप से चलाएं

सैंडबॉक्स, साथ में काम कर सकता है. इसलिए, नतीजे मिलने तक ब्लॉक हो सकता है. नीचे दिया गया कोड स्निपेट, Sandbox2 ऑब्जेक्ट के इंस्टैंशिएट और इसके सिंक्रोनस एक्ज़ीक्यूशन को दिखाता है. ज़्यादा जानकारी के लिए, स्टैटिक देखें.

#include "sandboxed_api/sandbox2/sandbox2.h"

sandbox2::Sandbox2 s2(std::move(executor), std::move(policy));
sandbox2::Result result = s2.Run();  // Synchronous
LOG(INFO) << "Result of sandbox execution: " << result.ToString();

एसिंक्रोनस रूप से चलाएं

आप सैंडबॉक्स को एसिंक्रोनस रूप से भी चला सकते हैं, ताकि कोई नतीजा मिलने तक ब्लॉक न हो. उदाहरण के लिए, Sandboxee से कम्यूनिकेट करते समय यह काम का होता है. नीचे दिया गया कोड स्निपेट, इस्तेमाल के इस उदाहरण को दिखाता है. ज़्यादा जानकारी के लिए, crc4 और टूल देखें.

#include "sandboxed_api/sandbox2/sandbox2.h"

sandbox2::Sandbox2 s2(std::move(executor), std::move(policy));
if (s2.RunAsync()) {
  // Communicate with sandboxee, use s2.Kill() to kill it if needed
  // ...
}
Sandbox2::Result result = s2.AwaitResult();
LOG(INFO) << "Final execution status: " << result.ToString();

5. सैंडबॉक्सी से संचार करना

डिफ़ॉल्ट रूप से, एक्ज़ीक्यूटर, फ़ाइल डिस्क्रिप्टर के ज़रिए Sandboxee से कम्यूनिकेट कर सकता है. आपको इन चीज़ों की ज़रूरत पड़ सकती है. उदाहरण के लिए, अगर आपको सिर्फ़ Sandboxee के साथ कोई फ़ाइल शेयर करनी है या Sandboxee का स्टैंडर्ड आउटपुट पढ़ना है.

हालांकि, इस बात की सबसे ज़्यादा संभावना है कि आपको एक्ज़ीक्यूटर और Sandboxee के बीच कम्यूनिकेशन के लिए, ज़्यादा पेचीदा लॉजिक की ज़रूरत हो. comms API (comms.h हेडर फ़ाइल देखें) का इस्तेमाल पूर्णांक, स्ट्रिंग, बाइट बफ़र, प्रोटोबफ़ या फ़ाइल डिस्क्रिप्टर को भेजने के लिए किया जा सकता है.

फ़ाइल डिस्क्रिप्टर शेयर करना

Inter-Process Communication API (ipc.h देखें) का इस्तेमाल करके, MapFd() या ReceiveFd() का इस्तेमाल किया जा सकता है:

  • एक्ज़ीक्यूटर से Sandboxee से फ़ाइल डिस्क्रिप्टर को मैप करने के लिए, MapFd() का इस्तेमाल करें. इसका इस्तेमाल, एक्ज़ीक्यूटर से खोली गई फ़ाइल को Sandboxee में इस्तेमाल करने के लिए शेयर करने के लिए किया जा सकता है. इसका एक उदाहरण स्टैटिक में देखा जा सकता है.

    // The executor opened /proc/version and passes it to the sandboxee as stdin
    executor->ipc()->MapFd(proc_version_fd, STDIN_FILENO);
    
  • सॉकेटपेयर एंडपॉइंट बनाने के लिए, ReceiveFd() का इस्तेमाल करें. इसका इस्तेमाल, Sandboxee के स्टैंडर्ड आउटपुट या स्टैंडर्ड गड़बड़ियों को पढ़ने के लिए किया जा सकता है. टूल में, इसे इस्तेमाल करने का एक उदाहरण देखा जा सकता है.

    // The executor receives a file descriptor of the sandboxee stdout
    int recv_fd1 = executor->ipc())->ReceiveFd(STDOUT_FILENO);
    

comms API का इस्तेमाल करना

Sandbox2 एक सुविधाजनक comms API उपलब्ध कराता है. यह एक्ज़ीक्यूटर और Sandboxee के बीच पूर्णांक, स्ट्रिंग या बाइट बफ़र शेयर करने का एक आसान और आसान तरीका है. नीचे कुछ कोड स्निपेट दिए गए हैं, जिन्हें crc4 के उदाहरण में देखा जा सकता है.

comms API के साथ शुरुआत करने के लिए, आपको पहले Sandbox2 ऑब्जेक्ट से comms ऑब्जेक्ट पाना होगा:

sandbox2::Comms* comms = s2.comms();

कम्यूनिकेशन ऑब्जेक्ट उपलब्ध होने पर, डेटा को 'भेजें*' फ़ैमिली के किसी एक फ़ंक्शन का इस्तेमाल करके, Sandboxee को भेजा जा सकता है. crc4 के उदाहरण में, comms API के इस्तेमाल का उदाहरण देखा जा सकता है. नीचे दिया गया कोड स्निपेट, इस उदाहरण का एक छोटा हिस्सा दिखाता है. एक्ज़ीक्यूटर, SendBytes(buf, size) के साथ unsigned char buf[size] भेजता है:

if (!(comms->SendBytes(static_cast<const uint8_t*>(buf), sz))) {
  /* handle error */
}

Sandboxee से डेटा पाने के लिए, Recv* के किसी एक फ़ंक्शन का इस्तेमाल करें. नीचे दिया गया कोड स्निपेट, crc4 के उदाहरण का हिस्सा है. एक्ज़ीक्यूटर को, साइन न किए गए 32-बिट पूर्णांक में चेकसम मिलता है: uint32_t crc4;

if (!(comms->RecvUint32(&crc4))) {
  /* handle error */
}

बफ़र के साथ डेटा शेयर करना

डेटा शेयर करने की एक और सुविधा है, ज़्यादा डेटा शेयर करने के लिए buffer API का इस्तेमाल करना. साथ ही, एक्ज़ीक्यूटर और Sandboxee के बीच बार-बार भेजी जाने वाली महंगी कॉपी से बचा जाना.

एक्ज़ीक्यूटर, पास किए जाने वाले साइज़ और डेटा के हिसाब से या सीधे फ़ाइल डिस्क्रिप्टर से बफ़र बनाता है और उसे एक्ज़ीक्यूटर में comms->SendFD() और सैंडबॉक्स में comms->RecvFD() का इस्तेमाल करके सैंडबॉक्सी को भेजता है.

नीचे दिए गए कोड स्निपेट में, आप एक्ज़ीक्यूटर का साइड देख सकते हैं. सैंडबॉक्स, एसिंक्रोनस रूप से चलता है और सैंडबॉक्स के साथ बफ़र के ज़रिए डेटा शेयर करता है:

// start the sandbox asynchronously
s2.RunAsync();

// instantiate the comms object
sandbox2::Comms* comms = s2.comms();

// random buffer data we want to send
constexpr unsigned char buffer_data[] = /* random data */;
constexpr unsigned int buffer_dataLen = 34;

// create sandbox2 buffer
absl::StatusOr<std::unique_ptr<sandbox2::Buffer>> buffer =
     sandbox2::Buffer::CreateWithSize(1ULL << 20 /* 1Mib */);
std::unique_ptr<sandbox2::Buffer> buffer_ptr = std::move(buffer).value();

// point to the sandbox2 buffer and fill with data
uint8_t* buf = buffer_ptr‑>data();
memcpy(buf, buffer_data, buffer_data_len);

// send the data to the sandboxee
comms‑>SendFd(buffer_ptr‑>fd());

Sandboxee की ओर, आपको एक बफ़र ऑब्जेक्ट बनाना होगा और एक्सक्यूटर के भेजे गए फ़ाइल डिस्क्रिप्टर से डेटा को पढ़ना होगा:

// establish the communication with the executor
int fd;
comms.RecvFD(&fd);

// create the buffer
absl::StatusOr<std::unique_ptr<sandbox2::Buffer>> buffer =
     sandbox2::Buffer::createFromFd(fd);

// get the data
auto buffer_ptr = std::move(buffer).value();
uint8_t* buf = buffer_ptr‑>data();

/* work with the buf object */

6. सैंडबॉक्स से बाहर निकलना

सैंडबॉक्स चलाने के तरीके के आधार पर (यह चरण देखें), आपको सैंडबॉक्स को खत्म करने के तरीके में बदलाव करना होगा. इस तरह सैंडबॉक्स को भी खत्म किया जा सकता है.

सिंक्रोनस रूप से चल रहे सैंडबॉक्स से बाहर निकलना

अगर सैंडबॉक्स को साथ में चलाया जा रहा है, तो सैंडबॉक्सी के खत्म होने पर ही रन चलेगा. इसलिए, खाता बंद करने के लिए आपको कोई और चरण देने की ज़रूरत नहीं है. नीचे दिया गया कोड स्निपेट यह स्थिति दिखाता है:

Sandbox2::Result result = s2.Run();
LOG(INFO) << "Final execution status: " << result.ToString();

एसिंक्रोनस रूप से चल रहे किसी सैंडबॉक्स से बाहर निकलना

अगर सैंडबॉक्स एसिंक्रोनस रूप से चल रहा है, तो बंद करने के दो विकल्प उपलब्ध हैं. सबसे पहले, आपको सैंडबॉक्सी के पूरा होने तक इंतज़ार करना होगा और उसके बाद आपको एक्ज़ीक्यूशन की आखिरी स्थिति मिल जाएगी:

sandbox2::Result result = s2.AwaitResult();
LOG(INFO) << "Final execution status: " << result.ToString();

इसके अलावा, आपके पास सैंडबॉक्सी को किसी भी समय बंद करने का विकल्प है. हालांकि, हमारा सुझाव है कि आप AwaitResult() को कॉल करें, क्योंकि इस बीच किसी अन्य वजह से सैंडबॉक्सी बंद हो सकती है:

s2.Kill();
sandbox2::Result result = s2.AwaitResult();
LOG(INFO) << "Final execution status: " << result.ToString();

7. टेस्ट

किसी भी दूसरे कोड की तरह, आपके सैंडबॉक्स को लागू करने के तरीके में टेस्ट होने चाहिए. सैंडबॉक्स की जांच का मकसद यह जांच करना नहीं है कि प्रोग्राम ठीक है या नहीं. हालांकि, इसकी मदद से यह जांच की जाती है कि सैंडबॉक्स किए गए प्रोग्राम, सैंडबॉक्स उल्लंघन जैसी समस्याओं के बिना चल सकते हैं या नहीं. इससे यह भी पक्का होता है कि सैंडबॉक्स की नीति सही है.

सैंडबॉक्स किए गए प्रोग्राम की जांच उसी तरह से की जाती है जैसे इसे प्रोडक्शन में चलाया जाता है. इसमें उन तर्कों और इनपुट फ़ाइलों की जांच की जाती है जिन्हें आम तौर पर प्रोसेस किया जाता है.

ये टेस्ट, सब-प्रोसेस में शेल टेस्ट या C++ टेस्ट करने जितना आसान हो सकते हैं. प्रेरणा के लिए उदाहरण देखें.

नतीजा

अब तक इसे पढ़ने के लिए धन्यवाद. हमें उम्मीद है कि आपको हमारी गाइड पसंद आई होगी. अब आप अपने सैंडबॉक्स बनाकर, अपने उपयोगकर्ताओं को सुरक्षित रख सकते हैं.

सैंडबॉक्स और नीतियां बनाना मुश्किल काम है. साथ ही, इसमें गड़बड़ियां भी आसानी से हो सकती हैं. सुरक्षित रहने के लिए, हमारा सुझाव है कि आप अपनी नीति और कोड की समीक्षा किसी सुरक्षा विशेषज्ञ से करें.