SELinux'u doğrulayın

Android, OEM'lerin SELinux uygulamalarını kapsamlı bir şekilde test etmesini kesinlikle önerir. Ü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 işlem genel SELinux modunu yazdırır: Enforcing veya Permissive. 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.

Reddedilenleri oku

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 dmesg için SELinux çıkışını incelemeli, herkese açık sürümden önce izinli modda ve nihai olarak uygulama moduna geçmeden önce ayarları hassaslaştırmalıdır. SELinux günlük mesajları avc: içerir ve bu nedenle grep ile kolayca bulunabilir. cat /proc/kmsg çalıştırarak devam eden ret günlüklerini veya cat /sys/fs/pstore/console-ramoops çalıştırarak önceki önyüklemeden ret günlüklerini yakalayabilirsiniz.

SELinux hata mesajları, günlüklerin dolmasını önlemek için başlatma tamamlandıktan sonra hız sınırlamasına tabidir. 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ı ihlal ettiği zamanı 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ı, yaptırım modunda 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. Sonundaki tclass ile birlikte (unix_stream_socket), kabaca neyin neyle yapıldığını gösterir. Bu durumda, bir unix akış yuvasına bağlanmaya çalışılıyordu.
  • scontext (u:r:shell:s0), işlemi hangi bağlamın başlattığını gösterir. Bu örnekte, bu 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.
  • En üstteki comm="ping", reddin oluşturulduğu anda çalıştırılmakta olan uygulama hakkında ek ipucu sağlar. 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: Yapılmak istenen işlem, köşeli parantezler, read write veya setenforce içinde vurgulanır.
  • İşlemi gerçekleştiren - scontext (kaynak bağlam) girişi, işlemi gerçekleştireni (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ünde bir nesne vardır.

Kullanıcı ve çekirdek yığınlarının dökümünü al

Bazı durumlarda, olay günlüğünde yer alan bilgiler, ret işleminin kaynağını belirlemek için yeterli olmaz. Reddedilme işleminin neden gerçekleştiğini daha iyi anlamak için çekirdek ve kullanıcı alanı dahil olmak üzere çağrı zincirini toplamak genellikle 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

  • Ö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 dalı da desteklenir. Cihazınızda izleme noktasının 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. Sonrasında 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 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, reddin gerçekleştiği çekirdeğe kadar başlatarak 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ı bölümüne bakın.

İzin verici ayarlara geçiş yapın

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

Alternatif olarak, çekirdek komut satırında (cihazın erken başlatılması sırasında):

androidboot.selinux=permissive
androidboot.selinux=enforcing

Alternatif olarak Android 12'de bootconfig üzerinden:

androidboot.selinux=permissive
androidboot.selinux=enforcing

audit2allow'u kullanma

audit2allow aracı dmesg reddi alır ve bunları ilgili SELinux politika ifadelerine dönüştürür. Bu nedenle, SELinux geliştirme sürecini büyük ölçüde hızlandırabilir.

Bu komutu kullanmak için:

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

Bununla birlikte, izinlerin aşırı kullanımı nedeniyle her bir potansiyel eklemeyi incelerken dikkatli olunması 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.