Memvalidasi SELinux

Android sangat menganjurkan OEM untuk menguji implementasi SELinux mereka secara menyeluruh. Saat produsen menerapkan SELinux, mereka harus menerapkan kebijakan baru ke kumpulan perangkat uji terlebih dahulu.

Setelah menerapkan kebijakan baru, pastikan SELinux berjalan dalam mode yang benar di perangkat dengan mengeluarkan perintah getenforce .

Ini mencetak mode SELinux global: Enforcing atau Permissive. Untuk menentukan mode SELinux untuk setiap domain, Anda harus memeriksa file yang sesuai atau menjalankan versi terbaru sepolicy-analyze dengan flag ( -p ) yang sesuai, yang ada di /platform/system/sepolicy/tools/ .

Membaca penolakan

Periksa kesalahan, yang dirutekan sebagai log peristiwa ke dmesg dan logcat dan dapat dilihat secara lokal di perangkat. Produsen harus memeriksa keluaran SELinux ke dmesg pada perangkat ini dan menyempurnakan pengaturan sebelum rilis publik dalam mode permisif dan akhirnya beralih ke mode penegakan. Pesan log SELinux berisi avc: dan dapat dengan mudah ditemukan dengan grep . Dimungkinkan untuk menangkap log penolakan yang sedang berlangsung dengan menjalankan cat /proc/kmsg atau untuk menangkap log penolakan dari boot sebelumnya dengan menjalankan cat /sys/fs/pstore/console-ramoops .

Dengan keluaran ini, produsen dapat dengan mudah mengidentifikasi ketika pengguna sistem atau komponen melanggar kebijakan SELinux. Produsen kemudian dapat memperbaiki perilaku buruk ini, baik dengan mengubah perangkat lunak, kebijakan SELinux, atau keduanya.

Secara khusus, pesan log ini menunjukkan proses apa yang akan gagal dalam mode penegakan dan alasannya. Berikut ini contohnya:

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

Interpretasikan output ini seperti ini:

  • { connectto } di atas mewakili tindakan yang diambil. Bersama dengan tclass di akhir ( unix_stream_socket ), ini memberi tahu Anda secara kasar apa yang sedang dilakukan untuk apa. Dalam hal ini, ada sesuatu yang mencoba menyambung ke soket aliran unix.
  • scontext (u:r:shell:s0) memberi tahu Anda konteks apa yang memulai tindakan. Dalam hal ini, ini adalah sesuatu yang berjalan sebagai shell.
  • tcontext (u:r:netd:s0) memberi tahu Anda konteks target tindakan. Dalam hal ini, itu adalah unix_stream_socket yang dimiliki oleh netd .
  • comm="ping" di bagian atas memberi Anda petunjuk tambahan tentang apa yang sedang dijalankan saat penolakan dibuat. Dalam hal ini, ini adalah petunjuk yang cukup bagus.

Contoh lain:

adb shell su root dmesg | grep 'avc: '

Keluaran:

<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

Berikut adalah elemen kunci dari penolakan ini:

  • Tindakan - tindakan yang dicoba disorot dalam tanda kurung, read write , atau setenforce .
  • Aktor - scontext (konteks sumber) mewakili aktor, dalam hal ini daemon rmt_storage .
  • Objek - tcontext (konteks target) mewakili objek yang sedang ditindaklanjuti, dalam hal ini kmem.
  • Hasil - tclass (kelas target) menunjukkan jenis objek yang ditindaklanjuti, dalam hal ini chr_file (perangkat karakter).

Membuang Tumpukan Pengguna dan Kernel

Dalam beberapa kasus, informasi yang terkandung dalam log peristiwa tidak cukup untuk menunjukkan dengan tepat asal penolakan. Seringkali berguna untuk mengumpulkan rantai panggilan, termasuk kernel dan ruang pengguna, untuk lebih memahami mengapa penolakan terjadi.

Kernel terbaru mendefinisikan sebuah tracepoint bernama avc:selinux_audited . Gunakan Android simpleperf untuk mengaktifkan tracepoint ini dan menangkap rantai panggilan.

Konfigurasi yang didukung

  • Kernel Linux >= 5.10, khususnya cabang utama Android Common Kernel dan android12-5.10 didukung. Cabang android12-5.4 juga didukung. Anda dapat menggunakan simpleperf untuk menentukan apakah tracepoint ditentukan pada perangkat Anda: adb root && adb shell simpleperf list | grep avc:selinux_audited . Untuk versi kernel lainnya, Anda dapat memilih commit dd81662 dan 30969bc .
  • Seharusnya dimungkinkan untuk mereproduksi acara yang Anda debug. Peristiwa waktu booting tidak didukung menggunakan simpleperf; namun Anda mungkin masih dapat memulai ulang layanan untuk memicu acara.

Menangkap rantai panggilan

Langkah pertama adalah merekam acara menggunakan simpleperf record :

adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"

Kemudian, peristiwa yang menyebabkan penolakan harus dipicu. Setelah itu, perekaman harus dihentikan. Dalam contoh ini, dengan menggunakan Ctrl-c , sampel seharusnya sudah diambil:

^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.

Akhirnya, simpleperf report dapat digunakan untuk memeriksa stacktrace yang ditangkap. Misalnya:

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

Rantai panggilan di atas adalah rantai panggilan kernel dan ruang pengguna terpadu. Ini memberi Anda pandangan yang lebih baik tentang aliran kode dengan memulai pelacakan dari ruang pengguna hingga ke kernel tempat penolakan terjadi. Untuk informasi lebih lanjut tentang simpleperf , lihat referensi perintah Simpleperf Executable

Beralih ke permisif

Penegakan SELinux dapat dinonaktifkan melalui ADB pada userdebug atau eng build. Untuk melakukannya, pertama-tama alihkan ADB ke root dengan menjalankan adb root . Kemudian, untuk menonaktifkan penegakan SELinux, jalankan:

adb shell setenforce 0

Atau di baris perintah kernel (selama pembukaan perangkat awal):

androidboot.selinux=permissive
androidboot.selinux=enforcing

Atau melalui bootconfig di Android 12:

androidboot.selinux=permissive
androidboot.selinux=enforcing

Menggunakan audit2allow

Alat audit2allow mengambil penolakan dmesg dan mengubahnya menjadi pernyataan kebijakan SELinux yang sesuai. Dengan demikian, ini dapat sangat mempercepat pengembangan SELinux.

Untuk menggunakannya, jalankan:

adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy

Namun demikian, kehati-hatian harus diberikan untuk memeriksa setiap kemungkinan tambahan untuk izin yang melampaui batas. Misalnya, memberi makan audit2allow penolakan rmt_storage yang ditampilkan sebelumnya menghasilkan pernyataan kebijakan SELinux yang disarankan berikut ini:

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

Ini akan memberikan rmt kemampuan untuk menulis memori kernel, lubang keamanan yang mencolok. Seringkali pernyataan audit2allow hanyalah titik awal. Setelah menggunakan pernyataan ini, Anda mungkin perlu mengubah domain sumber dan label target, serta memasukkan makro yang tepat, untuk sampai pada kebijakan yang baik. Terkadang penolakan yang diperiksa seharusnya tidak menghasilkan perubahan kebijakan sama sekali; alih-alih aplikasi yang menyinggung harus diubah.