Android, ओईएम को सलाह देता है कि वे SELinux को लागू करने से पहले, उसकी अच्छी तरह से जांच कर लें. डिवाइस बनाने वाली कंपनियों को SELinux लागू करते समय, सबसे पहले डिवाइसों के टेस्ट पूल पर नई नीति लागू करनी चाहिए.
नई नीति लागू करने के बाद, पक्का करें कि डिवाइस पर SELinux सही मोड में चल रहा हो. इसके लिए, getenforce कमांड जारी करें.
इससे, SELinux का ग्लोबल मोड प्रिंट होता है. यह मोड, नीति लागू करने वाला या नीति लागू न करने वाला हो सकता है. हर डोमेन के लिए SELinux मोड का पता लगाने के लिए, आपको उससे जुड़ी फ़ाइलों की जांच करनी होगी. इसके अलावा,
/platform/system/sepolicy/tools/ में मौजूद सही (-p) फ़्लैग के साथ sepolicy-analyze के नए वर्शन को भी चलाया जा सकता है.
अनुमति न मिलने की जानकारी
गड़बड़ियों की जांच करें. इन्हें इवेंट लॉग के तौर पर dmesg और logcat पर भेजा जाता है. साथ ही, इन्हें डिवाइस पर स्थानीय तौर पर देखा जा सकता है. डिवाइस बनाने वाली कंपनियों को, इन डिवाइसों पर SELinux के आउटपुट की जांच करनी चाहिए. साथ ही, सार्वजनिक तौर पर रिलीज़ करने से पहले, अनुमत मोड में सेटिंग को बेहतर बनाना चाहिए. इसके बाद, नीति लागू करने वाले मोड पर स्विच करना चाहिए.dmesg SELinux के लॉग मैसेज में avc: होता है. इसलिए, इन्हें grep की मदद से आसानी से ढूंढा जा सकता है. cat /proc/kmsg कमांड चलाकर, अनुमति न मिलने से जुड़े मौजूदा लॉग कैप्चर किए जा सकते हैं. इसके अलावा, cat /sys/fs/pstore/console-ramoops कमांड चलाकर, पिछले बूट से जुड़े अनुमति न मिलने के लॉग कैप्चर किए जा सकते हैं.
बूट होने की प्रोसेस पूरी होने के बाद, SELinux से जुड़ी गड़बड़ियों के मैसेज की दर सीमित कर दी जाती है, ताकि लॉग में बहुत ज़्यादा मैसेज न दिखें. यह पक्का करने के लिए कि आपको सभी ज़रूरी मैसेज दिखें, adb shell auditctl -r 0 चलाकर इस सुविधा को बंद किया जा सकता है.
इस आउटपुट की मदद से, मैन्युफ़ैक्चरर आसानी से यह पता लगा सकते हैं कि सिस्टम के उपयोगकर्ता या कॉम्पोनेंट, SELinux नीति का उल्लंघन कब कर रहे हैं. इसके बाद, डिवाइस बनाने वाली कंपनियां इस समस्या को ठीक कर सकती हैं. इसके लिए, वे सॉफ़्टवेयर, SELinux नीति या दोनों में बदलाव कर सकती हैं.
खास तौर पर, इन लॉग मैसेज से पता चलता है कि एनफ़ोर्सिंग मोड में कौनसी प्रोसेस पूरी नहीं होंगी और क्यों. उदाहरण के लिए:
avc: denied { connectto } for pid=2671 comm="ping" path="/dev/socket/dnsproxyd"
scontext=u:r:shell:s0 tcontext=u:r:netd:s0 tclass=unix_stream_socket
इस आउटपुट को इस तरह समझें:
- ऊपर दिया गया
{ connectto }, की जा रही कार्रवाई को दिखाता है. आखिर में मौजूदtclass(unix_stream_socket) के साथ मिलकर, यह बताता है कि किस चीज़ के लिए क्या किया जा रहा था. इस मामले में, कोई प्रोसेस यूनिक्स स्ट्रीम सॉकेट से कनेक्ट करने की कोशिश कर रही थी. -
scontext (u:r:shell:s0)से पता चलता है कि किस कॉन्टेक्स्ट में कार्रवाई शुरू की गई थी. इस मामले में, यह शेल के तौर पर चल रहा है. -
tcontext (u:r:netd:s0)से आपको कार्रवाई के टारगेट के बारे में पता चलता है. इस मामले में, यहnetdके मालिकाना हक वाला unix_stream_socket है. - सबसे ऊपर मौजूद
comm="ping"से आपको इस बारे में अतिरिक्त जानकारी मिलती है कि अस्वीकार किए जाने के समय कौनसी प्रोसेस चल रही थी. इस मामले में, यह एक बहुत अच्छा हिंट है.
एक और उदाहरण:
adb shell su root dmesg | grep 'avc: '
आउटपुट:
<5> type=1400 audit: avc: denied { read write } for pid=177
comm="rmt_storage" name="mem" dev="tmpfs" ino=6004 scontext=u:r:rmt:s0
tcontext=u:object_r:kmem_device:s0 tclass=chr_file
यहां अनुरोध अस्वीकार किए जाने की वजहें बताई गई हैं:
- कार्रवाई - की गई कार्रवाई को ब्रैकेट में हाइलाइट किया जाता है,
read writeयाsetenforce. - ऐक्टर -
scontext(सोर्स कॉन्टेक्स्ट) एंट्री, ऐक्टर को दिखाती है. इस मामले में, यहrmt_storageडेमॉन है. - ऑब्जेक्ट -
tcontext(टारगेट कॉन्टेक्स्ट) एंट्री, उस ऑब्जेक्ट को दिखाती है जिस पर कार्रवाई की जा रही है. इस मामले में, यह kmem है. - नतीजा -
tclass(टारगेट क्लास) एंट्री से पता चलता है कि किस तरह के ऑब्जेक्ट पर कार्रवाई की जा रही है. इस मामले में, यहchr_file(कैरेक्टर डिवाइस) है.
उपयोगकर्ता और कर्नल स्टैक डंप करना
कुछ मामलों में, इवेंट लॉग में मौजूद जानकारी से यह पता नहीं चलता कि अनुरोध को अस्वीकार क्यों किया गया. अक्सर, कॉल चेन की जानकारी इकट्ठा करना फ़ायदेमंद होता है. इसमें कर्नल और यूज़रस्पेस शामिल होते हैं. इससे यह समझने में मदद मिलती है कि अनुरोध को अस्वीकार क्यों किया गया.
हाल ही के कर्नल, avc:selinux_audited नाम का एक ट्रेसपॉइंट तय करते हैं. इस ट्रेसपॉइंट को चालू करने और कॉलचेन को कैप्चर करने के लिए, Android
simpleperf का इस्तेमाल करें.
काम करने वाला कॉन्फ़िगरेशन
- Linux कर्नेल >= 5.10, खास तौर पर Android Common Kernel की इन ब्रांच के साथ काम करता है:
mainline
और
android12-5.10.
android12-5.4
ब्रांच भी काम करती है.
simpleperfका इस्तेमाल करके यह पता लगाया जा सकता है कि आपके डिवाइस पर ट्रेसपॉइंट तय किया गया है या नहीं:adb root && adb shell simpleperf list | grep avc:selinux_audited. कर्नेल के अन्य वर्शन के लिए, dd81662 और 30969bc कमिट को चुना जा सकता है. - जिस इवेंट को डीबग किया जा रहा है उसे फिर से ट्रिगर किया जा सकता हो. simpleperf का इस्तेमाल करके, बूट टाइम इवेंट ट्रैक नहीं किए जा सकते. हालांकि, इवेंट को ट्रिगर करने के लिए, सेवा को फिर से शुरू किया जा सकता है.
कॉल चेन कैप्चर करना
पहला चरण, simpleperf record का इस्तेमाल करके इवेंट रिकॉर्ड करना है:
adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"
इसके बाद, उस इवेंट को ट्रिगर किया जाना चाहिए जिसकी वजह से अनुमति नहीं दी गई. इसके बाद, रिकॉर्डिंग बंद कर देनी चाहिए. इस उदाहरण में, Ctrl-c का इस्तेमाल करके सैंपल को कैप्चर किया जाना चाहिए था:
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
आखिर में, कैप्चर किए गए स्टैकट्रेस की जांच करने के लिए, simpleperf report का इस्तेमाल किया जा सकता है.
उदाहरण के लिए:
adb shell -t "cd /data/local/tmp && su root simpleperf report -g --full-callgraph"
[...]
Children Self Command Pid Tid Shared Object Symbol
100.00% 0.00% dmesg 3318 3318 /apex/com.android.runtime/lib64/bionic/libc.so __libc_init
|
-- __libc_init
|
-- main
toybox_main
toy_exec_which
dmesg_main
klogctl
entry_SYSCALL_64_after_hwframe
do_syscall_64
__x64_sys_syslog
do_syslog
selinux_syslog
slow_avc_audit
common_lsm_audit
avc_audit_post_callback
avc_audit_post_callback
ऊपर दी गई कॉल चेन, यूनिफ़ाइड कर्नल और यूज़रस्पेस कॉल चेन है. इससे आपको कोड फ़्लो की बेहतर जानकारी मिलती है. यह उपयोगकर्ताओं के स्पेस से लेकर कर्नल तक के ट्रेस को शुरू करता है. कर्नल में ही अनुरोध को अस्वीकार किया जाता है. simpleperf के बारे में ज़्यादा जानकारी के लिए, Simpleperf Executable commands reference देखें
अनुमति देने वाले मोड पर स्विच करना
userdebug या eng बिल्ड पर adb की मदद से, SELinux enforcement को बंद किया जा सकता है. इसके लिए, सबसे पहले adb root चलाकर, ADB को रूट पर स्विच करें. इसके बाद, SELinux एनफ़ोर्समेंट को बंद करने के लिए, यह कमांड चलाएं:
adb shell setenforce 0
इसके अलावा, डिवाइस को चालू करने के दौरान कर्नल कमांड लाइन पर भी इसे सेट किया जा सकता है:
androidboot.selinux=permissiveandroidboot.selinux=enforcing
इसके अलावा, Android 12 में bootconfig के ज़रिए भी ऐसा किया जा सकता है:
androidboot.selinux=permissiveandroidboot.selinux=enforcing
audit2allow का इस्तेमाल करना
audit2allow टूल, dmesg को अस्वीकार करता है और उन्हें SELinux नीति के स्टेटमेंट में बदलता है. इसलिए, इससे SELinux को डेवलप करने में काफ़ी मदद मिल सकती है.
इसका इस्तेमाल करने के लिए, यह कमांड चलाएँ:
adb pull /sys/fs/selinux/policyadb logcat -b events -d | audit2allow -p policy
हालांकि, हर संभावित बदलाव की जांच यह देखने के लिए की जानी चाहिए कि कहीं अनुमतियां बहुत ज़्यादा तो नहीं दी गई हैं. उदाहरण के लिए, audit2allow को पहले दिखाए गए rmt_storage अस्वीकार करने की वजह बताने पर, SELinux नीति का यह सुझाव मिलता है:
#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };
इससे rmt को कर्नल मेमोरी लिखने की अनुमति मिल जाएगी. यह सुरक्षा के लिहाज़ से एक बड़ी समस्या है. अक्सर audit2allow स्टेटमेंट सिर्फ़ शुरुआती जानकारी देते हैं. इन स्टेटमेंट का इस्तेमाल करने के बाद, आपको सोर्स डोमेन और टारगेट के लेबल में बदलाव करना पड़ सकता है. साथ ही, सही मैक्रो शामिल करनी पड़ सकती हैं, ताकि अच्छी नीति बनाई जा सके. कभी-कभी, अस्वीकार किए जाने की वजह की जांच करने पर, नीति में कोई बदलाव नहीं होना चाहिए. इसके बजाय, उल्लंघन करने वाले ऐप्लिकेशन में बदलाव किया जाना चाहिए.