सैंडबॉक्सिंग

इस लेख में Bazel में सैंडबॉक्स करने, sandboxfs इंस्टॉल करने, और अपने सैंडबॉक्सिंग एनवायरमेंट को डीबग करने के बारे में बताया गया है.

सैंडबॉक्सिंग, अनुमतियों पर पाबंदी लगाने की ऐसी रणनीति है जो प्रोसेस को एक-दूसरे से या सिस्टम में मौजूद संसाधनों से अलग करती है. Bazel के लिए, इसका मतलब फ़ाइल सिस्टम के ऐक्सेस को सीमित करना है.

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

सैंडबॉक्सिंग किसी भी तरीके से होस्ट एनवायरमेंट को नहीं छिपाता है. प्रोसेस, फ़ाइल सिस्टम की सभी फ़ाइलों को बिना किसी शुल्क के ऐक्सेस कर सकती हैं. हालांकि, उपयोगकर्ता नेमस्पेस के साथ काम करने वाले प्लैटफ़ॉर्म पर, प्रोसेस अपनी वर्किंग डायरेक्ट्री से बाहर की किसी भी फ़ाइल में बदलाव नहीं कर सकती. इससे यह पक्का होता है कि बिल्ड ग्राफ़ में छिपी हुई डिपेंडेंसी नहीं होती हैं, जो बिल्ड के रीप्रॉड्यूसिबिलिटी पर असर डाल सकती हैं.

खास तौर पर, Bazel हर कार्रवाई के लिए एक execroot/ डायरेक्ट्री बनाता है. यह डायरेक्ट्री, एक्ज़ीक्यूशन के समय, कार्रवाई की वर्क डायरेक्ट्री के तौर पर काम करती है. execroot/ इसमें कार्रवाई के लिए सभी इनपुट फ़ाइलें होती हैं. साथ ही, ये किसी भी जनरेट किए गए आउटपुट के लिए कंटेनर के तौर पर काम करती हैं. इसके बाद, Bazel, ऑपरेटिंग सिस्टम से उपलब्ध कराई गई तकनीक का इस्तेमाल करता है. इसमें Linux पर कंटेनर और macOS पर sandbox-exec का इस्तेमाल किया जाता है, ताकि execroot/ में कार्रवाई को रोका जा सके.

सैंडबॉक्स करने की वजहें

  • ऐक्शन सैंडबॉक्सिंग के बिना, Bazel को यह पता नहीं चलता कि कोई टूल ऐसी इनपुट फ़ाइलों का इस्तेमाल करता है या नहीं जिनका एलान नहीं किया गया है (ऐसी फ़ाइलें जो किसी कार्रवाई की डिपेंडेंसी के तौर पर सूची में शामिल नहीं होती हैं). नहीं बताई गई इनपुट फ़ाइलों में से किसी एक में बदलाव होने पर, Bazel को अब भी लगता है कि बिल्ड अप-टू-डेट है और यह कार्रवाई को फिर से तैयार नहीं करेगा. इस वजह से, आपकी साइट का इंक्रीमेंटल (बढ़ने वाला) गलत बिल्ड हो सकता है.

  • कैश एंट्री का गलत तरीके से दोबारा इस्तेमाल करने से, रिमोट कैश मेमोरी के दौरान समस्याएं पैदा होती हैं. शेयर की गई कैश मेमोरी में सेव की गई खराब कैश एंट्री, प्रोजेक्ट के हर डेवलपर पर असर डालती है. साथ ही, पूरे रिमोट कैश को मिटाना संभव नहीं है.

  • सैंडबॉक्सिंग, रिमोट तरीके से एक्ज़ीक्यूशन की तरह काम करती है — अगर कोई बिल्ड सैंडबॉक्सिंग के साथ ठीक से काम करता है, तो हो सकता है कि वह रिमोट एक्ज़ीक्यूशन के साथ भी काम करे. सभी ज़रूरी फ़ाइलों (इसमें लोकल टूल भी शामिल हैं) को रिमोट तरीके से अपलोड करके, कंपाइल क्लस्टर के रखरखाव की लागत को काफ़ी कम किया जा सकता है. इसके लिए, क्लस्टर में हर मशीन पर टूल इंस्टॉल करने की ज़रूरत नहीं होती, जैसा कि हर बार नया कंपाइलर आज़माने या किसी मौजूदा टूल में बदलाव करने के लिए होता है.

किस सैंडबॉक्स रणनीति का इस्तेमाल करना चाहिए

रणनीति के फ़्लैग की मदद से, आपके पास यह चुनने का विकल्प होता है कि किस तरह के सैंडबॉक्सिंग का इस्तेमाल करना है. sandboxed रणनीति का इस्तेमाल करने पर, Bazel नीचे दिए गए सैंडबॉक्स में से एक को चुनता है. साथ ही, उसने कम हेमेटिक सैंडबॉक्स के बजाय ओएस वाले सैंडबॉक्स को प्राथमिकता दी. अगर आपने --worker_sandboxing फ़्लैग पास कर लिया है, तो नियमित तौर पर काम करने वाले वर्कर सामान्य सैंडबॉक्स में चलते हैं.

local (यानी standalone) रणनीति में किसी तरह की सैंडबॉक्सिंग नहीं की जाती. यह सिर्फ़ आपके फ़ाइल फ़ोल्डर के काम पर सेट वर्किंग डायरेक्ट्री के साथ कार्रवाई की कमांड लाइन को एक्ज़ीक्यूट करता है.

processwrapper-sandbox, सैंडबॉक्स करने की एक रणनीति है. इसे किसी भी "बेहतर" सुविधा की ज़रूरत नहीं है - यह किसी भी POSIX सिस्टम पर काम करनी चाहिए. यह एक ऐसी सैंडबॉक्स डायरेक्ट्री बनाता है जिसमें मूल सोर्स फ़ाइलों पर ले जाने वाले सिमलिंक होते हैं. साथ ही, यह ऐक्शन की कमांड लाइन को एक्ज़ीक्यूट करने के बजाय, इस डायरेक्ट्री पर सेट की गई वर्क डायरेक्ट्री के साथ एक्ज़ीक्यूट करता है. इसके बाद, पहचाने गए आउटपुट आर्टिफ़ैक्ट को सैंडबॉक्स से बाहर ले जाता है और सैंडबॉक्स को मिटा देता है. इससे, ऐक्शन को गलती से ऐसी किसी भी इनपुट फ़ाइल का इस्तेमाल करने से रोका जाता है जिसका एलान नहीं किया गया है. साथ ही, यह अज्ञात आउटपुट फ़ाइलों के साथ एक्ज़ीक्यूट को एक्सपोर्ट करने से भी रोकता है.

linux-sandbox एक कदम आगे जाता है और processwrapper-sandbox पर बढ़ता जाता है. जिस तरह Docker, हुड में काम करता है, उसी तरह यह Linux Namespaces (उपयोगकर्ता, माउंट, PID, नेटवर्क और IPC नेमस्पेस) का इस्तेमाल करके, होस्ट से कार्रवाई को अलग करता है. इसका मतलब है कि यह सैंडबॉक्स डायरेक्ट्री को छोड़कर, पूरे फ़ाइल सिस्टम को रीड-ओनली मोड में रखता है. इसलिए, कार्रवाई गलती से होस्ट फ़ाइल सिस्टम पर किसी भी तरह का बदलाव नहीं कर सकती. यह गलती से आपकी $HOME डायरेक्ट्री -rf' होने पर, गड़बड़ी की जांच जैसी स्थितियों से बचाता है. इसके अलावा, आपके पास कार्रवाई को नेटवर्क ऐक्सेस करने से रोकने का विकल्प भी है. linux-sandbox, कार्रवाई को किसी दूसरी प्रोसेस को देखने से रोकने और आखिर में होने वाली सभी प्रोसेस (यहां तक कि कार्रवाई के ज़रिए बनाए गए डीमन भी) को भरोसेमंद तरीके से बंद करने के लिए, पीआईडी नेमस्पेस का इस्तेमाल करता है.

darwin-sandbox मिलती-जुलती है, लेकिन macOS के लिए. यह Linux सैंडबॉक्स की तरह ही काम करने के लिए, Apple के sandbox-exec टूल का इस्तेमाल करता है.

ऑपरेटिंग सिस्टम की ओर से उपलब्ध कराए गए सिस्टम में पाबंदियों की वजह से, linux-sandbox और darwin-sandbox, दोनों "नेस्ट किए गए" सिस्टम में काम नहीं करते. Docker अपने कंटेनर मैजिक के लिए, Linux नेमस्पेस का भी इस्तेमाल करता है. इसलिए, linux-sandbox को Docker कंटेनर के अंदर आसानी से नहीं चलाया जा सकता, जब तक कि आप docker run --privileged का इस्तेमाल न करें. macOS पर, sandbox-exec को पहले से सैंडबॉक्स की जा रही प्रोसेस में नहीं चलाया जा सकता. इस तरह से, Bazel अपने-आप processwrapper-sandbox का इस्तेमाल करना शुरू कर देता है.

इसके बजाय, अगर आपको बिल्ड में गड़बड़ी दिखती है — जैसे कि बिना सख्ती से लागू की जाने वाली रणनीति की मदद से, गलती से कोड जनरेट नहीं करना है — तो कोड लागू करने की उन रणनीतियों की सूची में साफ़ तौर पर बदलाव करें जिनका इस्तेमाल Bazel, इस्तेमाल करने की कोशिश करता है (उदाहरण के लिए, bazel build --spawn_strategy=worker,linux-sandbox).

आम तौर पर, डाइनैमिक एक्ज़ीक्यूशन के लिए सैंडबॉक्सिंग की ज़रूरत होती है, ताकि स्थानीय एक्ज़ीक्यूशन किया जा सके. ऑप्ट आउट करने के लिए, --experimental_local_lockfree_output फ़्लैग पास करें. डाइनैमिक एक्ज़ीक्यूशन, बिना किसी रुकावट के नियमित तौर पर काम करने वाले वर्कर को सैंडबॉक्स करता है.

सैंडबॉक्सिंग के नुकसान

  • सैंडबॉक्सिंग के लिए अतिरिक्त सेटअप और टियरडाउन शुल्क देना पड़ता है. यह लागत कई चीज़ों पर निर्भर करती है, जैसे कि बिल्ड का आकार और होस्ट ओएस की परफ़ॉर्मेंस. Linux के लिए, सैंडबॉक्स वाले बिल्ड शायद ही कभी कुछ प्रतिशत से भी ज़्यादा धीमे हों. --reuse_sandbox_directories को सेट करने पर, सेटअप और टियरडाउन की लागत कम हो सकती है.

  • सैंडबॉक्सिंग, टूल में मौजूद किसी भी कैश मेमोरी को असरदार तरीके से बंद कर देता है. कमज़ोर सैंडबॉक्स गारंटी की कीमत पर, नियमित तौर पर काम करने वाले कर्मचारियों का इस्तेमाल करके इसे कम किया जा सकता है.

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

सैंडबॉक्स

sandboxfs, FUSE फ़ाइल सिस्टम है. यह सुविधा, मौजूदा फ़ाइल सिस्टम को मनचाहे तरीके से दिखाता है. इसमें समय की पाबंदी नहीं होती. Bazel हर कार्रवाई के लिए, sandboxfs का इस्तेमाल करके execroot/ को तुरंत जनरेट करता है. इस वजह से, हज़ारों सिस्टम कॉल करने में लगने वाला समय बचता है. ध्यान रखें कि execroot/ में आगे I/O, FUSE ओवरहेड की वजह से धीमा हो सकता है.

Sandboxfs इंस्टॉल करें

sandboxfs को इंस्टॉल करने और इसके साथ Bazel बिल्ड पूरा करने के लिए, यह तरीका अपनाएं:

डाउनलोड करें

डाउनलोड और इंस्टॉल करें sandboxfs, ताकि sandboxfs बाइनरी आपके PATH में आ सके.

रन sandboxfs

  1. (सिर्फ़ macOS के लिए) NexusFUSE इंस्टॉल करें.
  2. (सिर्फ़ macOS के लिए) चलाएं:

    sudo sysctl -w vfs.generic.osxfuse.tunables.allow_other=1
    

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

  3. --experimental_use_sandboxfs के साथ Bazel बिल्ड चलाएं.

    bazel build target --experimental_use_sandboxfs
    

किसी समस्या को हल करना

अगर आपको की जाने वाली कार्रवाइयों के लिए, darwin-sandbox या linux-sandbox के बजाय local दिखता है, तो इसका मतलब यह हो सकता है कि सैंडबॉक्सिंग बंद है. इसे चालू करने के लिए --genrule_strategy=sandboxed --spawn_strategy=sandboxed पास करें.

डीबग करना

सैंडबॉक्सिंग की समस्याओं को डीबग करने के लिए नीचे दी गई रणनीतियों का पालन करें.

बंद किए गए नेमस्पेस

Google Cubernetes Engine क्लस्टर नोड या Debian जैसे कुछ प्लैटफ़ॉर्म पर, सुरक्षा से जुड़ी समस्याओं की वजह से, उपयोगकर्ता के नेमस्पेस डिफ़ॉल्ट रूप से बंद कर दिए जाते हैं. अगर /proc/sys/kernel/unprivileged_userns_clone फ़ाइल मौजूद है और उसमें 0 है, तो उपयोगकर्ता नेमस्पेस चालू करने के लिए यह कमांड दें:

   sudo sysctl kernel.unprivileged_userns_clone=1

नियम निष्पादन की विफलता

सिस्टम सेटअप की वजह से हो सकता है कि सैंडबॉक्स, नियमों को लागू न कर पाए. अगर आपको namespace-sandbox.c:633: execvp(argv[0], argv): No such file or directory जैसा कोई मैसेज दिखता है, तो सामान्य नियमों के लिए --strategy=Genrule=local के साथ सैंडबॉक्स को बंद करें. साथ ही, दूसरे नियमों के लिए --spawn_strategy=local को बंद करें.

बिल्ड न हो पाने के मामलों के बारे में ज़्यादा जानकारी डीबग करने की सुविधा

अगर आपका बिल्ड फ़ेल हो जाता है, तो --verbose_failures और --sandbox_debug का इस्तेमाल करें, ताकि Bazel ठीक वही निर्देश दिखा सके जो आपके बिल्ड के असफल होने पर चलाया गया था. इसमें वह हिस्सा भी शामिल है जो सैंडबॉक्स को सेट अप करता है.

गड़बड़ी के मैसेज का उदाहरण:

ERROR: path/to/your/project/BUILD:1:1: compilation of rule
'//path/to/your/project:all' failed:

Sandboxed execution failed, which may be legitimate (such as a compiler error),
or due to missing dependencies. To enter the sandbox environment for easier
debugging, run the following command in parentheses. On command failure, a bash
shell running inside the sandbox will then automatically be spawned

namespace-sandbox failed: error executing command
  (cd /some/path && \
  exec env - \
    LANG=en_US \
    PATH=/some/path/bin:/bin:/usr/bin \
    PYTHONPATH=/usr/local/some/path \
  /some/path/namespace-sandbox @/sandbox/root/path/this-sandbox-name.params --
  /some/path/to/your/some-compiler --some-params some-target)

अब जनरेट की गई सैंडबॉक्स डायरेक्ट्री की जांच की जा सकती है. साथ ही, यह देखा जा सकता है कि Bazel ने कौनसी फ़ाइलें बनाई हैं. इसके बाद, यह देखने के लिए कि वह कैसे काम करता है, कमांड फिर से चलाएं.

ध्यान दें कि --sandbox_debug इस्तेमाल करने पर, Bazel सैंडबॉक्स डायरेक्ट्री को नहीं मिटाता है. अगर सक्रिय रूप से डीबग नहीं किया जाता है, तो आपको --sandbox_debug को बंद करना चाहिए, क्योंकि समय के साथ यह आपकी डिस्क में भर जाता है.