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

تحدد النواة الحديثة نقطة تتبع تسمى 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

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