يشجّع نظام التشغيل Android بشدة الشركات المصنّعة للأجهزة الأصلية على اختبار عمليات تنفيذ SELinux بدقة. عندما ينفّذ المصنّعون SELinux، عليهم تطبيق السياسة الجديدة أولاً على مجموعة اختبارية من الأجهزة.
بعد تطبيق سياسة جديدة، تأكَّد من أنّ SELinux يعمل في الوضع الصحيح على الجهاز من خلال تنفيذ الأمر getenforce
.
يطبع هذا الأمر وضع SELinux العام: إما Enforcing أو Permissive. لتحديد وضع SELinux لكل نطاق، يجب فحص الملفات ذات الصلة أو تشغيل أحدث إصدار من sepolicy-analyze
باستخدام العلامة المناسبة (-p
) المتوفرة في
/platform/system/sepolicy/tools/
.
عمليات رفض القراءة
ابحث عن الأخطاء التي يتم توجيهها كسجلات أحداث إلى 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
) إلى الإجراء الذي تم تنفيذه والمفعول به. في هذه الحالة، كانت هناك محاولة للاتصال بمقبس دفق Unix. - يخبرك
scontext (u:r:shell:s0)
بالسياق الذي بدأ الإجراء. في هذه الحالة، يكون هذا الإجراء هو ما يتم تنفيذه كواجهة. - تعرض السمة
tcontext (u:r:netd:s0)
سياق العنصر المستهدف من الإجراء. في هذه الحالة، يكون ذلك عبارة عن unix_stream_socket مملوك من خلالnetd
. - يمنحك
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 kernel 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 القابلة للتنفيذ.
التبديل إلى الوضع المتساهل
يمكن إيقاف فرض استخدام SELinux باستخدام adb على إصدارات userdebug أو eng. لإجراء ذلك،
عليك أولاً تبديل ADB إلى الجذر عن طريق تشغيل adb root
. بعد ذلك، لإيقاف فرض SELinux، نفِّذ ما يلي:
adb shell setenforce 0
أو في سطر أوامر النواة (أثناء إعداد الجهاز الأولي):
androidboot.selinux=permissive
androidboot.selinux=enforcing
أو من خلال bootconfig في Android 12:
androidboot.selinux=permissive
androidboot.selinux=enforcing
استخدام audit2allow
تتلقّى audit2allow
عمليات الرفض dmesg
وتحوّلها إلى بيانات سياسة SELinux ذات الصلة. وبالتالي، يمكن أن يؤدي ذلك إلى تسريع عملية تطوير SELinux بشكل كبير.
لاستخدامه، نفِّذ الأمر التالي:
adb pull /sys/fs/selinux/policy
adb 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
مجرد نقطة بداية. بعد استخدام هذه العبارات، قد تحتاج إلى تغيير نطاق المصدر وتصنيف الاستهداف، بالإضافة إلى دمج وحدات ماكرو مناسبة، للوصول إلى سياسة جيدة. في بعض الأحيان، يجب ألا يؤدي الرفض الذي يتم فحصه إلى أي تغييرات في السياسة، بل يجب تغيير التطبيق المخالف.