SELinux'u doğrulama

Android, OEM'lerin SELinux uygulamalarını kapsamlı bir şekilde test etmesini önemle tavsiye eder. Üreticiler SELinux'u uygularken yeni politikayı önce 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, genel SELinux modunu (Enforcing veya Permissive) yazdırır. Her alanın SELinux modunu belirlemek için ilgili dosyaları incelemeniz veya sepolicy-analyze'nın en yeni sürümünü /platform/system/sepolicy/tools/'de bulunan uygun (-p) işaretiyle çalıştırmanız gerekir.

Okunan reddedilenler

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 SELinux çıkışını incelemeli ve herkese açık sürümden önce ayarları izin verici modda hassaslaştırıp zorunlu kılma moduna geçmelidir.dmesg SELinux günlük iletileri avc: içerir ve bu nedenle 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 başlatma işleminden ret 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. İlgili tüm 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 zorunlu kılma modunda hangi işlemlerin 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. Sondaki tclass ile birlikte (unix_stream_socket), neyin neye yapıldığı 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 şey söz konusudur.
  • tcontext (u:r:netd:s0), işlemin hedefinin bağlamını gösterir. Bu durumda, bu netd 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: '

Çı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: Yapılmak istenen işlem parantez içinde vurgulanır, read write veya setenforce.
  • Aktör: scontext (kaynak bağlamı) girişi, aktörü (bu örnekte rmt_storage arka plan programını) temsil eder.
  • 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 örnekte chr_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 reddedilmesinin kaynağını 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 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'yı kullanabilirsiniz: adb root && adb shell simpleperf list | grep avc:selinux_audited. Diğer çekirdek sürümleri için dd81662 ve 30969bc kodlarını seçebilirsiniz.
  • Hata ayıklamasını yaptığınız etkinliği yeniden oluşturabilmeniz gerekir. Başlatma süresi etkinlikleri simpleperf kullanılarak 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, reddedilmeye neden olan etkinlik tetiklenmelidir. Ardından kayıt durdurulmalıdır. Bu örnekte, Ctrl-c kullanılarak örnek şu şekilde yakalanmış olmalıdır:

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

Son olarak, yakalanan yığın izini 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 arama zinciri, birleşik bir çekirdek ve kullanıcı alanı arama zinciridir. İzlemeyi, kullanıcı alanından başlayıp ret işleminin gerçekleştiği çekirdeğe kadar devam ettirerek kod akışını daha iyi görmenizi sağlar. simpleperf hakkında daha fazla bilgi için Simpleperf Executable commands reference (Simpleperf Yürütülebilir 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 kök olarak değiştirin. Ardından, SELinux zorunlu kılma özelliğini 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 aracılığıyla:

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ştirme sürecini büyük ölçüde hızlandırabilir.

Kullanmak için şu komutu ç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 incelenmesi gerekir. Örneğin, daha önce gösterilen audit2allow the rmt_storage reddiyle besleme yapıldığında aşağıdaki önerilen SELinux politika ifadesi elde edilir:

#============= 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.