Android zdecydowanie zachęca producentów OEM do dokładnego testowania implementacji SELinux. W miarę wdrażania SELinux producenci powinni najpierw zastosować nowe zasady w puli urządzeń testowych.
Po zastosowaniu nowych zasad sprawdź, czy SELinux działa na urządzeniu w odpowiednim trybie, wydając polecenie getenforce.
Wyświetla ono globalny tryb 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), która znajduje się w
/platform/system/sepolicy/tools/.
Odczytywanie odmów
Sprawdź, czy nie ma błędów, które są kierowane jako dzienniki zdarzeń do dmesg i logcat i są widoczne lokalnie na urządzeniu. Producenci powinni sprawdzić dane wyjściowe SELinux w dmesg na tych urządzeniach i dopracować ustawienia przed publicznym udostępnieniem w trybie Permissive i ewentualnym przejściem do trybu Enforcing. Komunikaty dziennika SELinux zawierają avc:, więc można je łatwo znaleźć za pomocą grep. Możesz rejestrować bieżące dzienniki odmów, uruchamiając cat /proc/kmsg, lub rejestrować dzienniki odmów z poprzedniego uruchomienia, uruchamiając cat /sys/fs/pstore/console-ramoops.
Komunikaty o błędach SELinux są ograniczane po zakończeniu uruchamiania, aby uniknąć przepełnienia dzienników. Aby mieć pewność, że widzisz wszystkie odpowiednie komunikaty, możesz wyłączyć to ograniczenie, uruchamiając adb shell auditctl -r 0.
Dzięki tym danym wyjściowym producenci mogą łatwo określić, kiedy użytkownicy lub komponenty systemu naruszają zasady SELinux. Producenci mogą następnie naprawić to niewłaściwe działanie, wprowadzając zmiany w oprogramowaniu, zasadach SELinux lub w obu tych elementach.
Te komunikaty dziennika wskazują, które procesy nie powiodłyby się w trybie Enforcing 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
Interpretuj te dane wyjściowe w ten sposób:
- Powyższy element
{ connectto }reprezentuje wykonywaną czynność. Wraz z elementemtclassna końcu (unix_stream_socket) informuje on, co i w jaki sposób zostało wykonane co. W tym przypadku coś próbowało połączyć się z gniazdem strumienia uniksowego. - Element
scontext (u:r:shell:s0)informuje, jaki kontekst zainicjował działanie. W tym przypadku jest to coś, co działa jako powłoka. - Element
tcontext (u:r:netd:s0)informuje o kontekście celu działania. W tym przypadku jest to gniazdo strumienia uniksowego należące donetd. - Element
comm="ping"u góry zawiera dodatkową wskazówkę dotyczącą tego, co było uruchomione w momencie wygenerowania odmowy. W tym przypadku jest to dość dobra wskazówka.
Inny przykład:
adb shell su root dmesg | grep 'avc: '
Dane wyjściowe:
<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 najważniejsze elementy tej odmowy:
- Działanie – próba działania jest wyróżniona w nawiasach,
read writelubsetenforce. - Użytkownik – wpis
scontext(kontekst źródłowy) reprezentuje użytkownika, w tym przypadku demonarmt_storage. - Obiekt – wpis
tcontext(kontekst docelowy) reprezentuje obiekt, na którym wykonywane jest działanie, w tym przypadku kmem. - Wynik – wpis
tclass(klasa docelowa) wskazuje typ obiektu, na którym wykonywane jest działanie, w tym przypadkuchr_file(urządzenie znakowe).
Zrzucanie stosów użytkownika 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 Androida simpleperf, aby włączyć ten punkt śledzenia i zarejestrować łańcuch wywołań.
Obsługiwana konfiguracja
- Obsługiwane są jądra Linuksa w wersji >= 5.10, w szczególności gałęzie Android Common Kernel
mainline
i
android12-5.10.
Obsługiwana jest też gałąź android12-5.4. Za pomocą
simpleperfmożesz sprawdzić, 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ć commity dd81662 i 30969bc. - Powinno być możliwe odtworzenie zdarzenia, które debugujesz. Zdarzenia podczas uruchamiania nie są obsługiwane przez simpleperf. Możesz jednak ponownie uruchomić usługę, aby wywołać zdarzenie.
Rejestrowanie łańcucha wywołań
Pierwszym krokiem jest zarejestrowanie zdarzenia za pomocą simpleperf record:
adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"
Następnie należy wywołać zdarzenie, które spowodowało odmowę. Potem należy zatrzymać nagrywanie. W tym przykładzie próbka powinna zostać zarejestrowana po naciśnięciu Ctrl-c:
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
Na koniec możesz użyć simpleperf report, aby sprawdzić zarejestrowany ślad 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. Dzięki temu uzyskasz lepszy wgląd w przepływ kodu, ponieważ śledzenie rozpoczyna się w przestrzeni użytkownika i prowadzi aż do jądra, w którym występuje odmowa. Więcej informacji o simpleperf znajdziesz w
dokumentacji poleceń wykonywalnych Simpleperf
Przełączanie na tryb Permissive
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=permissiveandroidboot.selinux=enforcing
Lub za pomocą bootconfig w Androidzie 12:
androidboot.selinux=permissiveandroidboot.selinux=enforcing
Używanie audit2allow
Narzędzie audit2allow pobiera odmowy dmesg i przekształca je w odpowiednie instrukcje zasad SELinux. Dzięki temu może znacznie przyspieszyć tworzenie SELinux.
Aby go użyć, uruchom:
adb pull /sys/fs/selinux/policyadb logcat -b events -d | audit2allow -p policy
Należy jednak dokładnie sprawdzić każde potencjalne dodanie pod kątem nadmiernych uprawnień. Na przykład przekazanie do audit2allow odmowy rmt_storage pokazanej wcześniej spowoduje wygenerowanie następującej sugerowanej instrukcji zasad SELinux:
#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };
Przyznałoby to rmt możliwość zapisywania pamięci jądra, co stanowi poważną lukę w zabezpieczeniach. Często audit2allow twierdzenia są tylko punktem początkowym. Po zastosowaniu tych instrukcji może być konieczne zmodyfikowanie domeny źródłowej i etykiety celu, a także uwzględnienie odpowiednich makr, aby uzyskać dobre zasady. Czasami sprawdzana odmowa nie powinna powodować żadnych zmian w zasadach. Zamiast tego należy zmienić aplikację, która spowodowała problem.