Android, OEM'lerin SELinux uygulamalarını ayrıntılı bir şekilde test etmelerini önemle tavsiye eder. Üreticiler SELinux'u uygularken yeni politikayı önce bir test cihazı havuzuna 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, genel SELinux modunu (Zorunlu veya İzin Veren) yazdırır. Her alanın SELinux modunu belirlemek için ilgili dosyaları incelemeniz veya sepolicy-analyze
'ın en son sürümünü
/platform/system/sepolicy/tools/
'da bulunan uygun (-p
) işaretiyle çalıştırmanız gerekir.
Reddetme mesajlarını okuma
dmesg
ve logcat
'e etkinlik günlükleri olarak yönlendirilen ve cihazda yerel olarak görüntülenebilen hataları kontrol edin. Üreticiler, bu cihazlarda SELinux çıkışını dmesg
olarak inceleyip herkese açık sürümden önce izin verici modda ayarları hassaslaştırıp zorunlu moduna geçmelidir. SELinux günlük mesajları avc:
içerdiğinden grep
ile kolayca bulunabilir. cat /proc/kmsg
komutunu çalıştırarak devam eden ret günlüklerini veya cat /sys/fs/pstore/console-ramoops
komutunu çalıştırarak önceki önyüklemeden ret günlüklerini yakalayabilirsiniz.
SELinux hata mesajları, günlüklerin tıkanmasını önlemek için önyükleme tamamlandıktan sonra hız sınırlamasına tabi tutulur. Alakalı tüm mesajları gördüğünüzden emin olmak için adb shell auditctl -r 0
'ü çalıştırarak bu özelliği devre dışı bırakabilirsiniz.
Bu çıkış 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.
Daha açık belirtmek gerekirse bu günlük mesajları, zorunlu modda hangi süreçlerin neden başarısız olacağını belirtir. Ö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 }
, yapılan işlemi temsil eder. Sonundakitclass
ile birlikte (unix_stream_socket
), kabaca neyin neyle yapıldığını gösterir. Bu durumda, bir unix akış soketine bağlanmaya çalışan bir şey vardı. -
scontext (u:r:shell:s0)
, işlemin hangi bağlamda başlatıldığını belirtir. Bu durumda, kabuk olarak çalışan bir şeydir. -
tcontext (u:r:netd:s0)
, işlemin hedefinin bağlamını belirtir. Bu durumda,netd
tarafından sahip olunan bir unix_stream_socket olur. - Üstteki
comm="ping"
, reddin oluşturulduğu sırada neyin çalıştırıldığı hakkında ek bir ipucu verir. Bu durumda oldukça iyi bir ipucu.
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 retin temel unsurları şunlardır:
- İşlem: Denenen işlem parantez içinde vurgulanır (
read write
veyasetenforce
). - Aktör:
scontext
(kaynak bağlamı) girişi, bu durumdarmt_storage
daemon'ı temsil eden aktörü belirtir. - 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ünde bir nesne vardır.
Kullanıcı ve çekirdek yığınlarını dökme
Bazı durumlarda, reddin kaynağını belirlemek için etkinlik günlüğündeki bilgiler yeterli olmaz. Reddetmenin nedenini daha iyi anlamak için genellikle çekirdek ve kullanıcı alanı da dahil olmak üzere çağrı zincirini toplamak yararlı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
'ü kullanın.
Desteklenen yapılandırma
- Özellikle Android Ortak Çekirdeği şu şubeleri olmak üzere mainline ve android12-5.10 dahil olmak üzere 5.10 ve üzeri sürümlerin Linux çekirdeği desteklenir.
android12-5.4 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 ile ilgili taahhütleri seçebilirsiniz. - Hata ayıkladığınız etkinliği yeniden oluşturmanız gerekir. simpleperf kullanılarak önyükleme zamanı etkinlikleri desteklenmez. Ancak etkinliği tetiklemek için hizmeti yeniden başlatabilirsiniz.
Ç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, reddin neden olduğu etkinlik tetiklenir. Ardından kayıt durdurulur. 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 izlemeyi 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 reddin gerçekleştiği çekirdeğe kadar devam ettirerek kod akışının daha iyi bir görünümünü sunar. simpleperf
hakkında daha fazla bilgi için Simpleperf yürütülebilir komutları referansı başlıklı makaleyi inceleyin.
İzin verici ayarlara geçin
SELinux yaptırımı, userdebug veya eng derlemelerinde adb ile devre dışı bırakılabilir. Bunun için önce adb root
komutunu çalıştırarak ADB'yi root'a geçirin. Ardından SELinux yaptırımını devre dışı bırakmak için şu komutu çalıştırın:
adb shell setenforce 0
Veya çekirdek komut satırında (cihazın ilk başlatılması sırasında):
androidboot.selinux=permissive
androidboot.selinux=enforcing
Alternatif olarak Android 12'deki bootconfig üzerinden de yapabilirsiniz:
androidboot.selinux=permissive
androidboot.selinux=enforcing
audit2allow'u kullanma
audit2allow
aracı, dmesg
retlerini alır ve bunları ilgili SELinux politika beyanlarına dönüştürür. Bu nedenle, SELinux geliştirme sürecini büyük ölçüde hızlandırabilir.
Bunu kullanmak için şu komutu çalıştırın:
adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy
Yine de her potansiyel eklemenin izinleri aşma açısından incelenmesi gerekir. Örneğin, daha önce gösterilen rmt_storage
reddi audit2allow
ile beslendiğinde aşağıdaki önerilen SELinux politika beyanı ortaya çıkar:
#============= shell ============== allow shell kernel:security setenforce; #============= rmt ============== allow rmt kmem_device:chr_file { read write };
Bu, rmt
'e çekirdek belleğine yazma yetkisi verir. Bu da bariz bir güvenlik açığıdır. audit2allow
ifadeleri genellikle yalnızca bir başlangıç noktasıdır. Bu ifadeleri kullandıktan sonra, iyi bir politikaya ulaşmak için kaynak alanını ve hedefin etiketini değiştirmeniz, ayrıca uygun makrolar eklemeniz gerekebilir. İncelenen ret, bazen politika değişikliğine yol açmaz. Bunun yerine, rahatsız edici uygulama değiştirilmelidir.