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) به شما می گوید که چه زمینه ای اقدام را آغاز کرده است. در این مورد این چیزی است که به عنوان پوسته در حال اجرا است.
  • tcontext (u:r:netd:s0) زمینه هدف عمل را به شما می گوید. در این مورد، این یک سوکت unix_stream_ متعلق به 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 برجسته می شود.
  • Actor - مدخل scontext (متن منبع) بازیگر را نشان می دهد، در این مورد دیمون rmt_storage .
  • Object - ورودی tcontext (متن هدف) نشان دهنده شی مورد عمل است، در این مورد kmem.
  • نتیجه - ورودی tclass (کلاس هدف) نشان دهنده نوع شیئی است که روی آن اعمال می شود، در این مورد chr_file (دستگاه کاراکتر).

پشته های کاربر و هسته را تخلیه کنید

در برخی موارد، اطلاعات موجود در گزارش رویداد برای مشخص کردن منشا انکار کافی نیست. جمع آوری زنجیره تماس، از جمله هسته و فضای کاربر، برای درک بهتر چرایی انکار، اغلب مفید است.

هسته های اخیر یک نقطه ردیابی به نام avc:selinux_audited را تعریف می کنند. از Android simpleperf برای فعال کردن این نقطه ردیابی و گرفتن callchain استفاده کنید.

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

  • هسته لینوکس >= 5.10، به ویژه شاخه های اصلی هسته مشترک Android و android12-5.10 پشتیبانی می شوند. شاخه android12-5.4 نیز پشتیبانی می شود. می توانید از simpleperf برای تعیین اینکه آیا نقطه ردیابی در دستگاه شما تعریف شده است استفاده کنید: adb root && adb shell simpleperf list | grep avc:selinux_audited . برای سایر نسخه‌های هسته، می‌توانید cherry pick commits 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 را با اجرای adb root به روت تغییر دهید. سپس، برای غیرفعال کردن اجرای SELinux، اجرا کنید:

adb shell setenforce 0

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

androidboot.selinux=permissive
androidboot.selinux=enforcing

یا از طریق bootconfig در اندروید 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 تنها یک نقطه شروع هستند. پس از استفاده از این عبارات، ممکن است لازم باشد دامنه منبع و برچسب هدف را تغییر دهید و همچنین ماکروهای مناسب را برای رسیدن به یک خط مشی خوب ترکیب کنید. گاهی اوقات انکار مورد بررسی به هیچ وجه نباید منجر به تغییر سیاستی شود. بلکه برنامه متخلف باید تغییر کند.