Memvalidasi SELinux

Android sangat mendorong OEM untuk menguji implementasi SELinux mereka secara menyeluruh. Sebagai produsen mengimplementasikan SELinux, mereka harus menerapkan ke kumpulan perangkat yang diuji terlebih dahulu.

Setelah menerapkan kebijakan baru, pastikan SELinux berjalan dengan di perangkat dengan memberikan perintah getenforce.

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

Penolakan pembacaan

Periksa apakah ada error, yang dirutekan sebagai log aktivitas ke dmesg dan logcat, serta dapat dilihat secara lokal di perangkat. Produsen harus memeriksa output SELinux ke dmesg di perangkat ini dan menyempurnakan setelan sebelum rilis publik dalam mode permisif dan pengalihan akhir hingga mode penerapan. Pesan log SELinux berisi avc:, dan demikian mungkin mudah ditemukan dengan grep. Dimungkinkan untuk menangkap log penolakan dengan menjalankan cat /proc/kmsg atau untuk mengambil log penolakan dari {i>booting<i} sebelumnya dengan menjalankan cat /sys/fs/pstore/console-ramoops.

Pesan error SELinux dibatasi kapasitasnya setelah booting selesai untuk menghindari swamping log. Untuk memastikan Anda melihat semua pesan yang relevan, nonaktifkan ini dengan menjalankan adb shell auditctl -r 0.

Dengan {i>output<i} ini, produsen dapat dengan mudah mengidentifikasi pengguna atau sistem apa komponen tersebut melanggar kebijakan SELinux. Produsen dapat memperbaiki perilaku buruk ini, baik oleh perubahan perangkat lunak, kebijakan SELinux, atau keduanya.

Secara khusus, pesan log ini menunjukkan proses apa yang akan gagal dalam mode penerapan 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 output ini seperti berikut:

  • { connectto } di atas menunjukkan tindakan yang dilakukan. Bersama dengan tclass di akhir (unix_stream_socket), memberi tahu Anda kira-kira apa yang sedang dilakukan menjadi apa. Dalam hal ini, ada sesuatu yang mencoba terhubung ke soket {i>stream <i}unix.
  • scontext (u:r:shell:s0) memberi tahu Anda konteks yang memulai tindakan tersebut. Di beberapa dalam hal ini adalah sesuatu yang berjalan sebagai {i>shell<i}.
  • tcontext (u:r:netd:s0) memberi tahu Anda konteks target tindakan. Di beberapa dalam hal ini, itu adalah unix_stream_socket yang dimiliki oleh netd.
  • comm="ping" di bagian atas memberikan petunjuk tambahan tentang hal yang dijalankan pada saat penolakan dibuat. Dalam hal ini, itu adalah petunjuk yang cukup bagus.

Contoh lain:

adb shell su root dmesg | grep 'avc: '

Output:

<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 utama dari penolakan ini:

  • Tindakan - tindakan yang dicoba ditandai dalam tanda kurung, read write atau setenforce.
  • Pelaku - Entri scontext (konteks sumber) mewakili pelaku, dalam hal ini daemon rmt_storage.
  • Objek - Entri tcontext (konteks target) mewakili objek yang ditindaklanjuti, dalam hal ini kmem.
  • Hasil - Entri tclass (class target) menunjukkan jenis objek yang ditindaklanjuti, dalam hal ini chr_file (perangkat karakter).

Membuang Stack Pengguna dan Kernel

Pada beberapa kasus, informasi yang ada di log peristiwa tidak cukup untuk menentukan asal penolakan. Hal ini sering kali berguna untuk mengumpulkan rantai panggilan, termasuk {i>kernel<i} dan {i>userspace<i}, untuk lebih memahami mengapa penolakan terjadi.

Kernel terbaru menentukan tracepoint bernama avc:selinux_audited. Gunakan Android simpleperf untuk mengaktifkan tracepoint ini dan merekam callchain.

Konfigurasi yang didukung

  • Kernel Linux >= 5.10, khususnya cabang Kernel Umum Android utama dan android12-5.10 didukung. Versi android12-5.4 juga didukung. Anda dapat menggunakan simpleperf untuk menentukan apakah tracepoint ditentukan di perangkat Anda: adb root && adb shell simpleperf list | grep avc:selinux_audited. Untuk versi {i>kernel<i} lainnya, Anda dapat memilih commit dd81662 dan 30969bc.
  • Anda harus dapat mereproduksi peristiwa yang sedang Anda proses debug. Peristiwa waktu booting tidak didukung menggunakan simpleperf; namun Anda mungkin masih dapat memulai ulang layanan untuk memicu acara tersebut.

Merekam rantai panggilan

Langkah pertama adalah merekam peristiwa 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, rekaman seharusnya akan dihentikan. Dalam contoh ini, dengan menggunakan Ctrl-c, contoh seharusnya telah diambil:

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

Terakhir, simpleperf report dapat digunakan untuk memeriksa stacktrace yang diambil. Sebagai contoh:

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 userspace dan kernel terpadu. Ini memberi Anda gambaran tampilan alur kode dengan memulai pelacakan dari ruang pengguna hingga ke {i>kernel<i} di mana penolakan terjadi. Untuk informasi selengkapnya tentang simpleperf, lihat Referensi perintah Simpleperf Executable

Beralih ke permisif

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

adb shell setenforce 0

Atau pada command line kernel (selama pemunculan perangkat awal):

androidboot.selinux=permissive
androidboot.selinux=enforcing

Atau melalui bootconfig di Android 12:

androidboot.selinux=permissive
androidboot.selinux=enforcing

Menggunakan audit2allow

Alat audit2allow menerima dmesg penolakan dan mengonversinya menjadi pernyataan kebijakan SELinux yang sesuai. Dengan demikian, dapat sangat mempercepat pengembangan SELinux.

Untuk menggunakannya, jalankan:

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

Meskipun demikian, hati-hati harus diperhatikan untuk memeriksa setiap potensi tambahan izin akses yang berlebihan. Misalnya, memberi makan audit2allow Penolakan rmt_storage yang ditampilkan sebelumnya menghasilkan hal berikut pernyataan kebijakan SELinux yang disarankan:

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

Ini akan memberi rmt kemampuan untuk menulis memori kernel, celah keamanan yang jelas. Sering kali pernyataan audit2allow hanya titik awal ini. Setelah menggunakan pernyataan ini, Anda mungkin perlu mengubah domain sumber dan label target, serta menyertakan label yang makro, untuk sampai pada kebijakan yang baik. Terkadang penolakan yang diperiksa harus tidak mengakibatkan perubahan kebijakan sama sekali; bukan aplikasi yang bermasalah harus diubah.