Memvalidasi SELinux

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

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

Ini mencetak mode SELinux global: Menegakkan atau Permisif. Untuk menentukan mode SELinux untuk setiap domain, Anda harus memeriksa file terkait atau menjalankan versi terbaru sepolicy-analyze dengan tanda ( -p ) yang sesuai, 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 yang akan dmesg pada perangkat ini dan menyempurnakan pengaturan sebelum dirilis ke publik dalam mode permisif dan pada akhirnya beralih ke mode penegakan. Pesan log SELinux berisi avc: sehingga 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 .

Pesan kesalahan SELinux dibatasi tingkatnya setelah booting selesai untuk menghindari membanjiri log. Untuk memastikan Anda melihat semua pesan yang relevan, Anda dapat menonaktifkannya dengan menjalankan adb shell auditctl -r 0 .

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 perubahan pada 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

Tafsirkan keluaran ini seperti ini:

  • Tanda { 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 terhadap 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 pada 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 - Entri scontext (konteks sumber) mewakili aktor, dalam hal ini daemon rmt_storage .
  • Objek - Entri tcontext (konteks target) mewakili objek yang ditindaklanjuti, dalam hal ini kmem.
  • Hasil - Entri 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 terdapat dalam log peristiwa tidak cukup untuk menunjukkan dengan tepat asal usul penolakan. Seringkali berguna untuk mengumpulkan rantai panggilan, termasuk kernel dan ruang pengguna, untuk lebih memahami mengapa penolakan terjadi.

Kernel terbaru mendefinisikan 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 .
  • Peristiwa yang sedang Anda debug seharusnya dapat direproduksi. Peristiwa waktu boot tidak didukung menggunakan simpleperf; namun Anda mungkin masih dapat memulai ulang layanan untuk memicu peristiwa tersebut.

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 tersebut harus dipicu. Setelah itu, perekaman harus dihentikan. Dalam contoh ini, dengan menggunakan Ctrl-c , sampel seharusnya diambil:

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

Terakhir, simpleperf report dapat digunakan untuk memeriksa pelacakan tumpukan yang ditangkap. Contohnya:

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 yang 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 selengkapnya tentang simpleperf , lihat referensi perintah Simpleperf Executable

Beralih ke permisif

Penegakan SELinux dapat dinonaktifkan melalui ADB pada userdebug atau build eng. Untuk melakukannya, pertama alihkan ADB ke root dengan menjalankan adb root . Kemudian, untuk menonaktifkan penerapan 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 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 potensi penambahan izin yang melampaui batas. Misalnya, memberi makan audit2allow penolakan rmt_storage yang ditunjukkan 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 memberi rmt kemampuan untuk menulis memori kernel, sebuah lubang keamanan yang mencolok. Seringkali pernyataan audit2allow hanya merupakan titik awal. Setelah menerapkan pernyataan ini, Anda mungkin perlu mengubah domain sumber dan label target, serta memasukkan makro yang tepat, untuk mendapatkan kebijakan yang baik. Terkadang penolakan yang diperiksa seharusnya tidak menghasilkan perubahan kebijakan sama sekali; sebaliknya aplikasi yang melanggar harus diubah.