SELinux नीति लिखें

Android Open Source Project (AOSP), उन ऐप्लिकेशन और सेवाओं के लिए एक बुनियादी नीति उपलब्ध कराता है जो सभी Android डिवाइसों पर काम करती हैं. AOSP में योगदान देने वाले लोग, इस नीति को समय-समय पर बेहतर बनाते रहते हैं. डिवाइस पर लागू होने वाली नीति के 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 के पास पहले से ही ज़रूरी अनुमतियां हैं.

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

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

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

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 डोमेन में सेवाएं चला सकते हैं. इसी तरह, अगर AOSP में तीसरे पक्ष के ऐप्लिकेशन के लिए नए डोमेन जोड़े जाते हैं, तो उनके पास भी 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 अस्वीकार होने का मतलब है कि गड़बड़ी वाली प्रोसेस, गलत यूनिक्स उपयोगकर्ता/ग्रुप/वर्ल्ड अनुमतियों के साथ फ़ाइल को ऐक्सेस करने की कोशिश कर रही है. dac_override अनुमति देने का मतलब यह नहीं है कि समस्या का समाधान हो गया है. इसके बजाय, फ़ाइल या प्रोसेस पर यूनिक्स अनुमतियां बदलें. init, vold, और installd जैसे कुछ डोमेन को, अन्य प्रोसेस की फ़ाइलों को ऐक्सेस करने के लिए, यूनिक्स फ़ाइल की अनुमतियों को बदलने की ज़रूरत होती है. ज़्यादा जानकारी के लिए, डैन वॉल्श का ब्लॉग देखें.