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. Sondakitclassile 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, bunetdtarafı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 writeveyasetenforce. - İşlemi gerçekleştiren:
scontext(kaynak bağlamı) girişi, işlemi gerçekleştireni temsil eder. Bu örnekte,rmt_storagearka 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
simpleperfkullanabilirsiniz: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=permissiveandroidboot.selinux=enforcing
Alternatif olarak Android 12'de bootconfig üzerinden:
androidboot.selinux=permissiveandroidboot.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/policyadb 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.