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

समस्या की शिकायत करें स्रोत देखें

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

डीबग करना

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

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

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 को बंद कर देना चाहिए, क्योंकि समय के साथ यह आपकी डिस्क को भर देता है.