SELinux را تایید کنید

اندروید قویاً تولیدکنندگان اصلی تجهیزات (OEM) را تشویق می‌کند تا پیاده‌سازی‌های SELinux خود را به‌طور کامل آزمایش کنند. همانطور که تولیدکنندگان SELinux را پیاده‌سازی می‌کنند، باید ابتدا سیاست جدید را روی مجموعه‌ای از دستگاه‌های آزمایشی اعمال کنند.

پس از اعمال یک سیاست جدید، با صدور دستور getenforce مطمئن شوید که SELinux در حالت صحیح روی دستگاه اجرا می‌شود.

این دستور حالت سراسری 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) به شما می‌گوید که چه context ای عمل را آغاز کرده است. در این مورد، این چیزی است که به عنوان shell اجرا می‌شود.
  • 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 برای فعال کردن این نقطه ردیابی و ثبت زنجیره فراخوانی استفاده کنید.

پیکربندی پشتیبانی شده

  • هسته لینوکس >= 5.10، به ویژه شاخه‌های هسته مشترک اندروید 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 برای بررسی stacktrace ضبط‌شده استفاده کرد. برای مثال:

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 root ، ADB را به root تغییر دهید. سپس، برای غیرفعال کردن اجرای SELinux، دستور زیر را اجرا کنید:

adb shell setenforce 0

یا در خط فرمان هسته (در هنگام بالا آمدن اولیه دستگاه):

androidboot.selinux=permissive
androidboot.selinux=enforcing

یا از طریق bootconfig در اندروید ۱۲:

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 denial که قبلاً نشان داده شده است، نتایجی را در عبارت سیاست پیشنهادی SELinux زیر نشان می‌دهد:

#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };

این امر به rmt امکان نوشتن حافظه هسته را می‌دهد که یک حفره امنیتی آشکار است. اغلب دستورات audit2allow تنها یک نقطه شروع هستند. پس از به‌کارگیری این دستورات، ممکن است لازم باشد دامنه منبع و برچسب هدف را تغییر دهید و همچنین ماکروهای مناسب را در آن بگنجانید تا به یک سیاست خوب برسید. گاهی اوقات، رد درخواست بررسی‌شده نباید منجر به هیچ تغییر سیاستی شود؛ بلکه باید برنامه متخلف تغییر کند.