Android, OEM'lerin SELinux uygulamalarını kapsamlı bir şekilde test etmelerini önemle tavsiye eder. Üreticiler SELinux'u uygularken önce yeni politikayı bir test cihazı grubuna uygulamalıdır.
Yeni bir politika uyguladıktan sonra getenforce
komutunu vererek SELinux'un cihazda doğru modda çalıştığından emin olun.
Bu komut, global SELinux modunu (Enforcing veya Permissive) yazdırır. Her alanın SELinux modunu belirlemek için ilgili dosyaları incelemeniz veya
/platform/system/sepolicy/tools/
içinde bulunan uygun (-p
) işaretiyle sepolicy-analyze
'nın en son sürümünü çalıştırmanız gerekir.
Okuma isteklerinin reddedilmesi
Hataları kontrol edin. Hatalar, dmesg
ve logcat
'ye etkinlik günlükleri olarak yönlendirilir ve cihazda yerel olarak görüntülenebilir. Üreticiler, bu cihazlarda dmesg
için SELinux çıkışını incelemeli ve herkese açık sürümden önce izin verici modda ayarları hassaslaştırıp zorunlu kılma moduna geçmelidir. SELinux günlük iletileri avc:
içerir ve bu nedenle grep
ile kolayca bulunabilir. cat /proc/kmsg
komutunu çalıştırarak devam eden reddetme günlüklerini veya cat /sys/fs/pstore/console-ramoops
komutunu çalıştırarak önceki başlatma işleminden reddetme günlüklerini yakalamak mümkündür.
SELinux hata mesajları, günlüklerin aşırı yüklenmesini önlemek için başlatma işlemi tamamlandıktan sonra sıklık sınırlamasına tabi tutulur. Tüm alakalı mesajları gördüğünüzden emin olmak için adb shell auditctl -r 0
komutunu çalıştırarak bu özelliği devre dışı bırakabilirsiniz.
Bu çıktı sayesinde üreticiler, sistem kullanıcılarının veya bileşenlerinin SELinux politikasını ne zaman ihlal ettiğini kolayca belirleyebilir. Üreticiler daha sonra yazılımda, SELinux politikasında veya her ikisinde de değişiklik yaparak bu kötü davranışı düzeltebilir.
Bu günlük mesajları, özellikle hangi işlemlerin zorunlu kılma modunda başarısız olacağını ve neden başarısız olacağını gösterir. Örnek:
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
Bu çıkışı şu şekilde yorumlayın:
- Yukarıdaki
{ connectto }
, gerçekleştirilen işlemi gösterir. Sondakitclass
ile birlikte (unix_stream_socket
), neyin neye uygulandığı hakkında kabaca bilgi verir. Bu durumda, bir şey bir Unix akış soketine bağlanmaya çalışıyordu. -
scontext (u:r:shell:s0)
simgesi, işlemi hangi bağlamın başlattığını gösterir. Bu durumda, kabuk olarak çalışan bir şeydir. -
tcontext (u:r:netd:s0)
, işlemin hedefinin bağlamını gösterir. Bu durumda, bunetd
tarafından sahip olunan bir unix_stream_socket'tir. - En üstteki
comm="ping"
, ret oluşturulduğu sırada neyin çalıştırıldığı hakkında ek bir ipucu verir. Bu durumda, oldukça iyi bir ipucu verilir.
Başka bir örnek:
adb shell su root dmesg | grep 'avc: '
Ses çıkışı:
<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
Bu ret yanıtındaki temel unsurlar şunlardır:
- İşlem: Denenen işlem parantez içinde vurgulanır,
read write
veyasetenforce
. - İşlemi gerçekleştiren:
scontext
(kaynak bağlamı) girişi, işlemi gerçekleştireni temsil eder. Bu örnekte,rmt_storage
arka plan programı işlemi gerçekleştirir. - Nesne:
tcontext
(hedef bağlam) girişi, üzerinde işlem yapılan nesneyi (bu örnekte kmem) temsil eder. - Sonuç:
tclass
(hedef sınıf) girişi, üzerinde işlem yapılan nesnenin türünü gösterir. Bu örnektechr_file
(karakter cihazı) türü kullanılmıştır.
Kullanıcı ve çekirdek yığınlarını dökme
Bazı durumlarda, olay günlüğünde yer alan bilgiler, erişim isteğinin reddedilme nedenini belirlemek için yeterli değildir. Reddetme işleminin neden gerçekleştiğini daha iyi anlamak için genellikle çekirdek ve kullanıcı alanı dahil olmak üzere çağrı zincirini toplamak faydalıdır.
Son çekirdekler, avc:selinux_audited
adlı bir izleme noktası tanımlar. Bu izleme noktasını etkinleştirmek ve çağrı zincirini yakalamak için Android simpleperf
'i kullanın.
Desteklenen yapılandırma
- Linux çekirdeği >= 5.10, özellikle Android Ortak Çekirdeği dalları
mainline
ve
android12-5.10
desteklenir.
android12-5.4
dalı da desteklenir. İzleme noktasının cihazınızda tanımlanıp tanımlanmadığını belirlemek için
simpleperf
kullanabilirsiniz:adb root && adb shell simpleperf list | grep avc:selinux_audited
. Diğer çekirdek sürümleri için dd81662 ve 30969bc taahhütlerini seçebilirsiniz. - Hata ayıklamasını yaptığınız etkinliğin yeniden oluşturulabilmesi gerekir. Başlatma süresi etkinlikleri simpleperf kullanılarak desteklenmez. Ancak hizmeti yeniden başlatarak etkinliği tetikleyebilirsiniz.
Çağrı zincirini yakalama
İlk adım, etkinliği simpleperf record
kullanarak kaydetmektir:
adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"
Ardından, reddedilmeye neden olan etkinlik tetiklenmelidir. Ardından kayıt durdurulmalıdır. Bu örnekte, Ctrl-c
kullanılarak örnek yakalanmış olmalıdır:
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
Son olarak, yakalanan yığın izlemesini incelemek için simpleperf report
kullanılabilir.
Örneğin:
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
Yukarıdaki çağrı zinciri, birleşik bir çekirdek ve kullanıcı alanı çağrı zinciridir. İzlemeyi kullanıcı alanından başlayıp ret işleminin gerçekleştiği çekirdeğe kadar götürerek kod akışını daha iyi görmenizi sağlar. simpleperf
hakkında daha fazla bilgi için Simpleperf Executable commands reference (Simpleperf Executable komutları referansı) başlıklı makaleyi inceleyin.
İzin vericiye geçiş yapma
SELinux zorunluluğu, userdebug veya eng derlemelerinde adb ile devre dışı bırakılabilir. Bunu yapmak için önce adb root
komutunu çalıştırarak ADB'yi root'a geçirin. Ardından, SELinux zorunlu kılmasını devre dışı bırakmak için şu komutu çalıştırın:
adb shell setenforce 0
Veya çekirdek komut satırında (erken cihaz başlatma sırasında):
androidboot.selinux=permissive
androidboot.selinux=enforcing
Alternatif olarak Android 12'de bootconfig üzerinden:
androidboot.selinux=permissive
androidboot.selinux=enforcing
audit2allow aracını kullanma
audit2allow
aracı, dmesg
retlerini alır ve bunları karşılık gelen SELinux politika ifadelerine dönüştürür. Bu nedenle, SELinux geliştirmeyi büyük ölçüde hızlandırabilir.
Kullanmak için şunu çalıştırın:
adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy
Bununla birlikte, her olası eklemenin aşırı izinler açısından incelenmesine özen gösterilmelidir. Örneğin, daha önce gösterilen audit2allow
the
rmt_storage
reddiyle ilgili feed'in kullanılması, aşağıdaki önerilen SELinux politikası ifadesiyle sonuçlanır:
#============= shell ============== allow shell kernel:security setenforce; #============= rmt ============== allow rmt kmem_device:chr_file { read write };
Bu, rmt
'ya çekirdek belleğine yazma olanağı tanır. Bu da büyük bir güvenlik açığıdır. audit2allow
ifadeleri genellikle yalnızca bir başlangıç noktasıdır. Bu ifadeleri kullandıktan sonra iyi bir politika oluşturmak için kaynak alanını ve hedefin etiketini değiştirmeniz, ayrıca uygun makroları eklemeniz gerekebilir. Bazen incelenen ret, politika değişikliklerine yol açmamalıdır. Bunun yerine, ihlalde bulunan uygulama değiştirilmelidir.