التحقق من صحة SELinux

يشجع 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. يمكن للمصنعين بعد ذلك إصلاح هذا السلوك السيئ ، إما عن طريق التغييرات في البرنامج أو سياسة 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) بسياق هدف الإجراء. في هذه الحالة ، هذا هو مقبس 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 (جهاز حرف).

إغراق المستخدم و Kernel Stacks

في بعض الحالات ، لا تكون المعلومات الواردة في سجل الأحداث كافية لتحديد أصل الرفض. غالبًا ما يكون من المفيد تجميع سلسلة الاستدعاء ، بما في ذلك kernel و userspace ، لفهم سبب حدوث الرفض بشكل أفضل.

تحدد النوى الحديثة نقطة تتبع تسمى avc:selinux_audited . استخدم Android simpleperf لتمكين نقطة التتبع هذه والتقاط سلسلة الاستدعاء.

التكوين المدعوم

  • Linux kernel> = 5.10 ، ولا سيما فروع Android Common Kernel الرئيسية و android12-5.10 مدعومان . يتم دعم فرع android12-5.4 أيضًا. يمكنك استخدام simpleperf لتحديد ما إذا كانت نقطة التتبع محددة على جهازك: adb root && adb shell simpleperf list | grep avc:selinux_audited . بالنسبة لإصدارات kernel الأخرى ، يمكنك اختيار تنفيذي 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

سلسلة الاستدعاء أعلاه عبارة عن سلسلة استدعاء موحدة kernel و userspace. يمنحك عرضًا أفضل لتدفق الشفرة عن طريق بدء التتبع من مساحة المستخدمين وصولاً إلى النواة حيث يحدث الرفض. لمزيد من المعلومات حول simpleperf ، راجع مرجع أوامر Simpleperf القابلة للتنفيذ

التحول إلى التساهل

يمكن تعطيل فرض SELinux عبر ADB على userdebug أو eng builds. للقيام بذلك ، قم أولاً بتحويل ADB إلى الجذر عن طريق تشغيل adb root . بعد ذلك ، لتعطيل فرض SELinux ، قم بتشغيل:

adb shell setenforce 0

أو في سطر أوامر kernel (أثناء طرح الجهاز مبكرًا):

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 القدرة على كتابة ذاكرة kernel ، وهو ثغرة أمنية صارخة. غالبًا ما تكون بيانات audit2allow مجرد نقطة انطلاق. بعد استخدام هذه العبارات ، قد تحتاج إلى تغيير المجال المصدر وتسمية الهدف ، بالإضافة إلى دمج وحدات الماكرو المناسبة للوصول إلى سياسة جيدة. في بعض الأحيان ، لا ينبغي أن يؤدي الرفض قيد الفحص إلى أي تغييرات في السياسة على الإطلاق ؛ بل يجب تغيير التطبيق المخالف.