Walidacja SELinux

Android zdecydowanie zachęca producentów OEM do dokładnego testowania ich implementacji SELinux. Ponieważ producenci wdrażają SELinux, powinni najpierw zastosować nową politykę do testowej puli urządzeń.

Po zastosowaniu nowej polityki upewnij się, że SELinux działa we właściwym trybie na urządzeniu, wydając polecenie getenforce .

Spowoduje to wydrukowanie globalnego trybu SELinux: Enforcing lub Permissive. Aby określić tryb SELinux dla każdej domeny, musisz sprawdzić odpowiednie pliki lub uruchomić najnowszą wersję sepolicy-analyze z odpowiednią flagą ( -p ) obecną w /platform/system/sepolicy/tools/ .

Czytanie odmów

Sprawdź błędy, które są kierowane jako dzienniki zdarzeń do dmesg i logcat i są widoczne lokalnie na urządzeniu. Producenci powinni sprawdzić wyjście SELinux do dmesg na tych urządzeniach i dopracować ustawienia przed publicznym udostępnieniem w trybie zezwalającym i ewentualnym przejściem do trybu wymuszania. Komunikaty dziennika SELinux zawierają avc: i dlatego można je łatwo znaleźć za pomocą grep . Możliwe jest przechwycenie bieżących dzienników odmowy, uruchamiając cat /proc/kmsg lub przechwycenie dzienników odmowy z poprzedniego uruchomienia, uruchamiając cat /sys/fs/pstore/console-ramoops .

Dzięki tym wynikom producenci mogą łatwo zidentyfikować, kiedy użytkownicy lub komponenty systemu naruszają zasady SELinux. Producenci mogą następnie naprawić to złe zachowanie, wprowadzając zmiany w oprogramowaniu, polityce SELinux lub jedno i drugie.

W szczególności te komunikaty dziennika wskazują, które procesy nie powiodą się w trybie wymuszania i dlaczego. Oto przykład:

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

Zinterpretuj ten wynik w ten sposób:

  • { connectto } powyżej reprezentuje podjętą akcję. Razem z tclass na końcu ( unix_stream_socket ) informuje z grubsza, co zostało zrobione i z czym. W tym przypadku coś próbowało połączyć się z gniazdem strumienia uniksowego.
  • scontext (u:r:shell:s0) mówi, jaki kontekst zainicjował akcję. W tym przypadku jest to coś działającego jako powłoka.
  • tcontext (u:r:netd:s0) informuje o kontekście celu akcji. W tym przypadku jest to unix_stream_socket należący do netd .
  • comm="ping" na górze daje dodatkową wskazówkę na temat tego, co było uruchamiane w momencie generowania odmowy. W tym przypadku to całkiem dobra wskazówka.

Inny przykład:

adb shell su root dmesg | grep 'avc: '

Wyjście:

<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

Oto kluczowe elementy tego zaprzeczenia:

  • Akcja - próba akcji jest wyróżniona w nawiasach, read write lub setenforce .
  • Aktorscontext (kontekst źródłowy) reprezentuje aktora, w tym przypadku demona rmt_storage .
  • Obiekt - tcontext (kontekst docelowy) reprezentuje obiekt, na którym działa, w tym przypadku kmem.
  • Wynik — wpis tclass (klasa docelowa) wskazuje typ obiektu, na którym będzie działać, w tym przypadku chr_file (urządzenie znakowe).

Zrzucanie stosów użytkowników i jądra

W niektórych przypadkach informacje zawarte w dzienniku zdarzeń nie wystarczają do określenia źródła odmowy. Często przydatne jest zebranie łańcucha wywołań, w tym jądra i przestrzeni użytkownika, aby lepiej zrozumieć, dlaczego doszło do odmowy.

Najnowsze jądra definiują punkt śledzenia o nazwie avc:selinux_audited . Użyj simpleperf dla systemu Android, aby włączyć ten punkt śledzenia i przechwycić łańcuch połączeń.

Obsługiwana konfiguracja

  • Jądro Linux >= 5.10, w szczególności obsługiwane są gałęzie wspólnego jądra Androida mainline i android12-5.10 . Obsługiwana jest również gałąź android12-5.4 . Możesz użyć simpleperf , aby określić, czy punkt śledzenia jest zdefiniowany na twoim urządzeniu: adb root && adb shell simpleperf list | grep avc:selinux_audited . W przypadku innych wersji jądra możesz wybrać wisienki commit dd81662 i 30969bc .
  • Powinno być możliwe odtworzenie debugowanego zdarzenia. Zdarzenia czasu rozruchu nie są obsługiwane przez simpleperf; jednak nadal możesz być w stanie ponownie uruchomić usługę, aby wyzwolić zdarzenie.

Przechwytywanie łańcucha połączeń

Pierwszym krokiem jest nagranie zdarzenia za pomocą simpleperf record :

adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"

Następnie powinno zostać wywołane zdarzenie, które spowodowało odmowę. Następnie nagrywanie powinno zostać zatrzymane. W tym przykładzie przy użyciu Ctrl-c próbka powinna zostać przechwycona:

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

Wreszcie, simpleperf report może być użyty do sprawdzenia przechwyconego śladu stosu. Na przykład:

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

Powyższy łańcuch wywołań to ujednolicony łańcuch wywołań jądra i przestrzeni użytkownika. Daje lepszy widok na przepływ kodu, rozpoczynając śledzenie od przestrzeni użytkownika aż do jądra, w którym następuje odmowa. Więcej informacji na temat simpleperf można znaleźć w podręczniku Simpleperf Executable — polecenia

Przełączam na tolerancję

Wymuszanie SELinux można wyłączyć za pomocą ADB w kompilacjach userdebug lub eng. Aby to zrobić, najpierw przełącz ADB na root, uruchamiając adb root . Następnie, aby wyłączyć wymuszanie SELinux, uruchom:

adb shell setenforce 0

Lub w wierszu poleceń jądra (podczas wczesnego uruchamiania urządzenia):

androidboot.selinux=permissive
androidboot.selinux=enforcing

Lub przez bootconfig w Androidzie 12:

androidboot.selinux=permissive
androidboot.selinux=enforcing

Korzystanie z audit2allow

Narzędzie audit2allow pobiera odmowy dmesg i konwertuje je na odpowiednie deklaracje polityki SELinux. W związku z tym może znacznie przyspieszyć rozwój SELinux.

Aby z niego skorzystać, uruchom:

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

Niemniej jednak należy zachować ostrożność, aby zbadać każdy potencjalny dodatek pod kątem przekroczenia uprawnień. Na przykład karmienie audit2allow pozwala na odmowę rmt_storage pokazaną wcześniej w następującej sugerowanej deklaracji polityki SELinux:

#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };

Dałoby to rmt możliwość zapisywania pamięci jądra, rażącą lukę w zabezpieczeniach. Często instrukcje audit2allow są tylko punktem wyjścia. Po zastosowaniu tych instrukcji może być konieczna zmiana domeny źródłowej i etykiety celu, a także włączenie odpowiednich makr, aby uzyskać dobrą politykę. Czasami badana odmowa nie powinna w ogóle powodować żadnych zmian w polityce; należy raczej zmienić obraźliwy wniosek.