تشجّع Android بشدة الشركات المصنّعة للأجهزة الأصلية على اختبار عمليات تنفيذ SELinux بدقة. عندما تنفّذ الشركات المصنّعة SELinux، عليها تطبيق السياسة الجديدة على مجموعة اختبارية من الأجهزة أولاً.
بعد تطبيق سياسة جديدة، تأكَّد من أنّ SELinux يعمل في الوضع الصحيح على الجهاز عن طريق تنفيذ الأمر getenforce.
يطبع هذا الأمر وضع SELinux العام: إما "فرض" أو "متساهل". لتحديد وضع 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 مملوكًا لـ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. استخدِم simpleperf من Android لتفعيل نقطة التتبُّع هذه وتسجيل سلسلة طلبات الإجراءات.
الإعدادات المتوافقة
- يتوافق النظام مع Linux kernel >= 5.10، وخاصةً الفروع الرئيسية
mainline
و
android12-5.10
من Android Common Kernel.
يتوافق النظام أيضًا مع الفرع 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=permissiveandroidboot.selinux=enforcing
أو من خلال bootconfig في Android 12:
androidboot.selinux=permissiveandroidboot.selinux=enforcing
استخدام audit2allow
تأخذ أداة audit2allow عمليات الرفض من dmesg وتحوّلها إلى عبارات سياسة SELinux المقابلة. على هذا النحو، يمكن أن يؤدي ذلك إلى تسريع عملية تطوير SELinux بشكلٍ كبير.
لاستخدامها، شغِّل:
adb pull /sys/fs/selinux/policyadb logcat -b events -d | audit2allow -p policy
ومع ذلك، يجب توخي الحذر لفحص كل إضافة محتملة بحثًا عن الأذونات المفرطة. على سبيل المثال، يؤدي إدخال رفض rmt_storage الذي تم عرضه سابقًا إلى audit2allow إلى عبارة سياسة SELinux المقترَحة التالية:
#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };
سيمنح ذلك rmt إمكانية كتابة ذاكرة النواة، ما يمثّل ثغرة أمنية صارخة. غالبًا ما تكون عبارات audit2allow مجرد نقطة بداية. بعد استخدام هذه العبارات، قد تحتاج إلى تغيير نطاق المصدر وتصنيف الهدف، بالإضافة إلى دمج وحدات ماكرو مناسبة، للوصول إلى سياسة جيدة. في بعض الأحيان، يجب ألا يؤدي الرفض الذي يتم فحصه إلى أي تغييرات في السياسة على الإطلاق، بل يجب تغيير التطبيق المخالف.