Memvalidasi SELinux

Android sangat menyarankan OEM untuk menguji penerapan SELinux mereka secara menyeluruh. Saat produsen mengimplementasikan SELinux, mereka harus menerapkan kebijakan baru ke kumpulan pengujian perangkat terlebih dahulu.

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

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

Membaca penolakan

Periksa 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 menyaring setelan sebelum rilis publik dalam mode permisif dan peralihan ke mode penerapan. Pesan log SELinux berisi avc:, sehingga mudah ditemukan dengan grep. Anda dapat menangkap log penolakan yang sedang berlangsung dengan menjalankan cat /proc/kmsg atau mencatat log penolakan dari booting sebelumnya dengan menjalankan cat /sys/fs/pstore/console-ramoops.

Pesan error SELinux dibatasi kapasitasnya setelah booting selesai agar tidak membanjiri log. Untuk memastikan Anda melihat semua pesan yang relevan, Anda dapat menonaktifkannya dengan menjalankan adb shell auditctl -r 0.

Dengan output ini, produsen dapat dengan mudah mengidentifikasi kapan pengguna atau komponen sistem melanggar kebijakan SELinux. Produsen kemudian dapat memperbaiki perilaku buruk ini, baik dengan perubahan software, kebijakan SELinux, atau keduanya.

Secara khusus, pesan log ini menunjukkan proses apa yang akan gagal dalam mode penerapan beserta 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 mewakili tindakan yang dilakukan. Bersama dengan tclass di akhir (unix_stream_socket), kode ini memberi tahu Anda secara kasar apa yang sedang dilakukan dan 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. 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, 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:

  • Action - upaya tindakan 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 sedang ditindaklanjuti, dalam hal ini chr_file (perangkat karakter).

Men-dump stack pengguna dan kernel

Dalam beberapa kasus, informasi yang terdapat dalam log peristiwa tidak cukup untuk menunjukkan asal penolakan. Mengumpulkan rantai panggilan, termasuk kernel dan userspace sering kali berguna untuk lebih memahami alasan terjadinya penolakan.

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 Android Common Kernel mainline dan android12-5.10 didukung. Cabang 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 kernel lainnya, Anda dapat memilih commit dd81662 dan 30969bc.
  • Anda seharusnya dapat mereproduksi peristiwa yang Anda debug. Peristiwa waktu booting tidak didukung menggunakan simpleperf; tetapi Anda mungkin masih dapat memulai ulang layanan untuk memicu peristiwa 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, perekaman harus 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 kernel dan ruang pengguna terpadu. Ini memberi Anda tampilan alur kode yang lebih baik dengan memulai rekaman aktivitas dari userspace hingga ke kernel tempat proses penolakan terjadi. Untuk informasi selengkapnya tentang simpleperf, lihat Referensi perintah yang dapat dieksekusi Simpleperf

Beralih ke permisif

Penerapan SELinux dapat dinonaktifkan dengan adb di debug pengguna atau build ing. Untuk melakukannya, alihkan ADB ke root terlebih dahulu dengan menjalankan adb root. Kemudian, untuk menonaktifkan penerapan SELinux, 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 mengambil penolakan dmesg dan mengonversinya menjadi pernyataan kebijakan SELinux yang sesuai. Dengan demikian, hal ini dapat sangat mempercepat pengembangan SELinux.

Untuk menggunakannya, jalankan:

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

Namun, Anda harus berhati-hati untuk memeriksa setiap potensi penambahan izin yang terlalu luas. Misalnya, memberi feed audit2allow penolakan rmt_storage yang ditampilkan sebelumnya akan menghasilkan pernyataan kebijakan SELinux yang disarankan berikut:

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

Hal ini akan memberi rmt kemampuan untuk menulis memori kernel, yang merupakan lubang keamanan yang mencolok. Sering kali, pernyataan audit2allow hanyalah titik awal. Setelah menerapkan pernyataan ini, Anda mungkin perlu mengubah domain sumber dan label target, serta menyertakan makro yang tepat, untuk menghasilkan kebijakan yang baik. Terkadang, penolakan yang sedang diperiksa seharusnya tidak menghasilkan perubahan kebijakan apa pun; aplikasi yang melanggar harus diubah.