SELinux नीति लिखें

Android Open Source Project (AOSP), उन ऐप्लिकेशन और सेवाओं के लिए एक बुनियादी नीति उपलब्ध कराता है जो सभी Android डिवाइसों पर काम करती हैं. एओएसपी में योगदान देने वाले लोग, इस नीति को नियमित तौर पर बेहतर बनाते हैं. डिवाइस पर लागू होने वाली नीति के 90 से 95% हिस्से में मुख्य नीति शामिल होगी. बाकी 5 से 10% हिस्से में, डिवाइस के हिसाब से किए गए बदलाव शामिल होंगे. इस लेख में, डिवाइस के हिसाब से किए गए इन कस्टमाइज़ेशन, डिवाइस के हिसाब से नीति लिखने के तरीके, और इस दौरान आने वाली कुछ समस्याओं के बारे में बताया गया है.

डिवाइस को चालू करना

डिवाइस के हिसाब से नीति लिखते समय, यह तरीका अपनाएं.

अनुमति वाले मोड में चलाना

जब कोई डिवाइस अनुमति वाले मोड में होता है, तो अनुमति न मिलने की जानकारी को लॉग किया जाता है, लेकिन उसे लागू नहीं किया जाता. अनुमति मोड की दो वजहें हैं:

  • अनुमति वाले मोड से यह पक्का होता है कि नीति लागू होने की प्रोसेस, डिवाइस के चालू होने से जुड़े अन्य टास्क में देरी न करे.
  • लागू किए गए अनुरोध को अस्वीकार करने पर, हो सकता है कि अस्वीकार किए गए अन्य मैसेज छिपा दिए जाएं. उदाहरण के लिए, फ़ाइल का ऐक्सेस पाने के लिए, आम तौर पर डायरेक्ट्री खोजी जाती है, फ़ाइल खोली जाती है, और फिर फ़ाइल को पढ़ा जाता है. नीति उल्लंघन ठीक करने के लिए, सिर्फ़ डायरेक्ट्री खोज की सुविधा को ब्लॉक किया जाएगा. अनुमति मोड से यह पक्का किया जाता है कि अनुरोध अस्वीकार किए जाने पर सभी लोग इसे देख सकें.

किसी डिवाइस को अनुमति वाले मोड में डालने का सबसे आसान तरीका, कर्नल कमांड लाइन का इस्तेमाल करना है. इसे डिवाइस की BoardConfig.mk फ़ाइल में जोड़ा जा सकता है: platform/device/<vendor>/<target>/BoardConfig.mk. कमांड लाइन में बदलाव करने के बाद, make clean और फिर make bootimage करें. इसके बाद, नई बूट इमेज को फ़्लैश करें.

इसके बाद, अनुमति वाले मोड की पुष्टि करने के लिए:

adb shell getenforce

ग्लोबल परमिसिव मोड में दो हफ़्ते तक रहना सही होता है. ज़्यादातर गड़बड़ियों को ठीक करने के बाद, नीति उल्लंघन ठीक करने के मोड पर वापस जाएं और गड़बड़ियों को ठीक करें. जिन डोमेन या सेवाओं के लिए अब भी अनुमति नहीं मिल रही है या जिन पर अब भी काफ़ी काम चल रहा है उन्हें कुछ समय के लिए अनुमति वाले मोड में रखा जा सकता है. हालांकि, उन्हें जल्द से जल्द नीति उल्लंघन ठीक करने वाले मोड में वापस ले आना चाहिए.

जल्द से जल्द लागू करना

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

मौजूदा नीति हटाना या मिटाना

किसी नए डिवाइस पर, डिवाइस के हिसाब से नीति बनाने की कई वजहें हैं. इनमें ये शामिल हैं:

मुख्य सेवाओं में की गई समस्याओं को हल करने की कोशिश

मुख्य सेवाओं से जनरेट होने वाली गड़बड़ियों को आम तौर पर, फ़ाइल को लेबल करके ठीक किया जाता है. उदाहरण के लिए:

avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0”
dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0
tclass=chr_file permissive=1
avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs"
scontext=u:r:mediaserver:s0
tcontext=u:object_r:device:s0 tclass=chr_file permissive=1

को सही तरीके से लेबल करके पूरी तरह से ठीक किया गया है /dev/kgsl-3d0. इस उदाहरण में, tcontext device है. यह डिफ़ॉल्ट कॉन्टेक्स्ट दिखाता है, जहां /dev में मौजूद हर चीज़ को तब तक “ डिवाइस” लेबल मिलता है, जब तक कि कोई ज़्यादा सटीक लेबल असाइन नहीं किया जाता. यहां सिर्फ़ audit2allow के आउटपुट को स्वीकार करने से एक गलत और बहुत ज़्यादा अनुमति देने वाला नियम बनेगा.

इस तरह की समस्या को हल करने के लिए, फ़ाइल को ज़्यादा सटीक लेबल दें. इस मामले में, यह लेबल gpu_device है. इसके लिए, कोई और अनुमति नहीं चाहिए. ऐसा इसलिए है, क्योंकि मुख्य नीति में, gpu_device को ऐक्सेस करने के लिए, mediaserver के पास पहले से ही ज़रूरी अनुमतियां हैं.

डिवाइस के हिसाब से बनाई गई अन्य फ़ाइलें, जिन्हें मुख्य नीति में तय किए गए टाइप के हिसाब से लेबल किया जाना चाहिए:

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

नई सेवाओं को लेबल करना और अस्वीकार किए गए अनुरोधों को ठीक करना

init से लॉन्च की गई सेवाओं को अपने SELinux डोमेन में चलाना ज़रूरी है. यहां दिए गए उदाहरण में, सेवा “foo” को उसके अपने SELinux डोमेन में रखा गया है और उसे अनुमतियां दी गई हैं.

यह सेवा, हमारे डिवाइस की init.device.rc फ़ाइल में इस तरह लॉन्च की गई है:

service foo /system/bin/foo
    class core
  1. नया डोमेन "foo" बनाएं

    यहां दिए गए कॉन्टेंट के साथ, device/manufacturer/device-name/sepolicy/foo.te फ़ाइल बनाएं:

    # foo service
    type foo, domain;
    type foo_exec, exec_type, file_type;
    
    init_daemon_domain(foo)
    

    यह foo SELinux डोमेन का शुरुआती टेंप्लेट है. इसमें, उस एक्सीक्यूटेबल की खास कार्रवाइयों के आधार पर नियम जोड़े जा सकते हैं.

  2. लेबल /system/bin/foo

    device/manufacturer/device-name/sepolicy/file_contexts में यह जानकारी जोड़ें:

    /system/bin/foo   u:object_r:foo_exec:s0
    

    इससे यह पक्का होता है कि एक्सीक्यूटेबल को सही तरीके से लेबल किया गया है, ताकि SELinux सेवा को सही डोमेन में चला सके.

  3. बूट और सिस्टम इमेज बनाएं और उन्हें फ़्लैश करें.
  4. डोमेन के लिए SELinux के नियमों को बेहतर बनाएं.

    ज़रूरी अनुमतियां तय करने के लिए, 'अस्वीकार' का इस्तेमाल करें. audit2allow टूल, अच्छे दिशा-निर्देश देता है. हालांकि, इसका इस्तेमाल सिर्फ़ नीति लिखने के लिए करें. सिर्फ़ आउटपुट कॉपी न करें.

लागू करने के मोड पर वापस स्विच करना

अनुमति वाले मोड में समस्या हल करना ठीक है, लेकिन जल्द से जल्द नीति उल्लंघन ठीक करने वाले मोड पर स्विच करें और उसमें बने रहें.

आम तौर पर होने वाली गलतियां

डिवाइस के हिसाब से नीतियां लिखते समय होने वाली आम गलतियों को ठीक करने के कुछ तरीके यहां दिए गए हैं.

नेगेटिव शब्दों का ज़रूरत से ज़्यादा इस्तेमाल करना

यहां दिए गए उदाहरण के नियम की तुलना, मुख्य दरवाज़े को लॉक करने और खिड़कियों को खुला छोड़ने से की जा सकती है:

allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms

इसका मकसद साफ़ है: तीसरे पक्ष के ऐप्लिकेशन के अलावा, सभी के पास डीबग डिवाइस का ऐक्सेस हो सकता है.

यह नियम कुछ मामलों में गलत है. untrusted_app को बाहर रखना आसान है, क्योंकि सभी ऐप्लिकेशन isolated_app डोमेन में सेवाएं चला सकते हैं. इसी तरह, अगर तीसरे पक्ष के ऐप्लिकेशन के लिए नए डोमेन एओएसपी में जोड़े जाते हैं, तो उनके पास भी scary_debug_device का ऐक्सेस होता है. नियम बहुत ज़्यादा अनुमति देता है. ज़्यादातर डोमेन को इस डीबगिंग टूल का ऐक्सेस मिलने से फ़ायदा नहीं होगा. नियम को इस तरह लिखा जाना चाहिए कि सिर्फ़ उन डोमेन को अनुमति मिले जिनके लिए ऐक्सेस की ज़रूरत है.

प्रोडक्शन में डीबग करने की सुविधाएं

प्रोडक्शन बिल्ड में डीबग करने की सुविधाएं और उनकी नीति मौजूद नहीं होनी चाहिए.

सबसे आसान विकल्प यह है कि डीबग करने की सुविधा को सिर्फ़ तब चालू करें, जब adb root और adb shell setenforce 0 जैसे eng/userdebug बिल्ड पर SELinux बंद हो.

डीबग करने की अनुमतियों को userdebug_or_eng स्टेटमेंट में शामिल करना, एक और सुरक्षित विकल्प है.

पॉलिसी साइज़ एक्सप्लोज़न

Characterizing SEAndroid Policies in the Wild में, डिवाइस की नीति को पसंद के मुताबिक बनाने के बढ़ते रुझान के बारे में बताया गया है. डिवाइस के हिसाब से बनी नीति, किसी डिवाइस पर चल रही कुल नीति का 5 से 10% हिस्सा होनी चाहिए. 20%से ज़्यादा बदलावों में, ज़्यादा से ज़्यादा विशेषाधिकार वाले डोमेन और ऐसी नीति शामिल होती है जो लागू नहीं है.

ग़ैर-ज़रूरी तौर पर बड़ी नीति:

  • जब नीति रैम डिस्क में मौजूद होती है और कर्नेल मेमोरी में लोड होती है, तो मेमोरी पर डबल हिट लेता है.
  • ज़्यादा स्टोरेज की ज़रूरत होती है, क्योंकि इसमें बड़ी bootimage होती है.
  • इससे रनटाइम नीति लुकअप के समय पर असर पड़ता है.

नीचे दिए गए उदाहरण में ऐसे दो डिवाइस दिखाए गए हैं जिनमें मैन्युफ़ैक्चरर की बनाई गई नीति का, 50% और 40% ऑन-डिवाइस नीति शामिल है. नीति को फिर से लिखने पर, सुरक्षा में काफ़ी सुधार हुए हैं. साथ ही, सुविधाओं में कोई कमी नहीं आई है. इस बारे में यहां बताया गया है. (तुलना करने के लिए, AOSP डिवाइस Shamu और Flounder शामिल किए गए हैं.)

पहला चित्र: सुरक्षा ऑडिट के बाद, डिवाइस के हिसाब से नीति के साइज़ की तुलना.

पहली इमेज. सुरक्षा ऑडिट के बाद, डिवाइस के हिसाब से बनी नीति के साइज़ की तुलना.

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

dac_override सुविधा दें

dac_override अस्वीकार किए जाने का मतलब है कि आपत्तिजनक प्रोसेस, Unix उपयोगकर्ता/ग्रुप/दुनिया की गलत अनुमतियों वाली फ़ाइल को ऐक्सेस करने की कोशिश कर रही है. dac_override की अनुमति कभी नहीं देना, करीब-करीब सही समाधान नहीं होता. इसके बजाय, फ़ाइल या प्रोसेस पर यूनिक्स अनुमतियां बदलें. init, vold, और installd जैसे कुछ डोमेन को, अन्य प्रोसेस की फ़ाइलों को ऐक्सेस करने के लिए, यूनिक्स फ़ाइल की अनुमतियों को बदलने की ज़रूरत होती है. ज़्यादा जानकारी के लिए, डैन वॉल्श का ब्लॉग देखें.