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

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

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

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

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

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

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

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

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

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

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

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

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

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

linux-sandbox एक कदम आगे बढ़कर processwrapper-sandbox के सबसे ऊपर बन जाता है. Docker की तरह ही, यह भी होस्ट से कार्रवाई को अलग करने के लिए, Linux नेमस्पेस (उपयोगकर्ता, माउंट, पीआईडी, नेटवर्क, और आईपीसी नेमस्पेस) का इस्तेमाल करता है. इसका मतलब है कि सैंडबॉक्स डायरेक्ट्री को छोड़कर, पूरे फ़ाइल सिस्टम को रीड-ओनली मोड में बदल दिया जाता है. इसलिए, यह कार्रवाई होस्ट के फ़ाइल सिस्टम में गलती से कुछ भी बदलाव नहीं कर सकती. इससे, गड़बड़ी की जांच जैसी स्थितियों से बचा जा सकता है. ऐसा गलती से आपकी $HOME डायरेक्ट्री को RM -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 का इस्तेमाल करने के लिए अपने-आप स्विच हो जाता है.

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

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

सैंडबॉक्सिंग की समस्याएं

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

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

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

sandboxfs

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

sandboxfs इंस्टॉल करना

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

डाउनलोड करें

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

sandboxfs चलाएं

  1. (सिर्फ़ macOS के लिए) OSXFUSE इंस्टॉल करें.
  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 Kubernetes 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 को बंद करना चाहिए, क्योंकि इससे आपकी डिस्क समय के साथ भर जाती है.