Android zdecydowanie zachęca producentów OEM do dokładnego testowania implementacji SELinux. Producenci wdrażający SELinux powinni najpierw zastosować nowe zasady na puli urządzeń testowych.
Po zastosowaniu nowych zasad upewnij się, że SELinux działa na urządzeniu w odpowiednim trybie, wydając polecenie getenforce
.
Wyświetla globalny tryb SELinux: Enforcing lub Permissive. Aby określić tryb SELinux dla każdej domeny, musisz sprawdzić odpowiednie pliki lub uruchomić najnowszą wersję narzędzia sepolicy-analyze
z odpowiednią flagą (-p
), która znajduje się w
/platform/system/sepolicy/tools/
.
Odczytywanie odmów
Sprawdź błędy, które są kierowane jako logi zdarzeń do dmesg
i logcat
i można je wyświetlać lokalnie na urządzeniu. Producenci powinni sprawdzić dane wyjściowe SELinux na tych urządzeniach i dopracować ustawienia przed udostępnieniem ich publicznie w trybie zezwalającym, a następnie przełączyć się na tryb egzekwowania.dmesg
Wiadomości dziennika SELinux zawierają avc:
, więc można je łatwo znaleźć za pomocą grep
. Możesz rejestrować bieżące logi odmowy, uruchamiając polecenie cat /proc/kmsg
, lub rejestrować logi odmowy z poprzedniego uruchomienia, uruchamiając polecenie cat /sys/fs/pstore/console-ramoops
.
Komunikaty o błędach SELinux są ograniczane po zakończeniu rozruchu, aby uniknąć przepełnienia dzienników. Aby mieć pewność, że widzisz wszystkie istotne wiadomości, możesz wyłączyć tę funkcję, uruchamiając adb shell auditctl -r 0
.
Dzięki temu producenci mogą łatwo określić, kiedy użytkownicy systemu lub komponenty naruszają zasady SELinux. Producenci mogą wtedy naprawić to nieprawidłowe działanie, wprowadzając zmiany w oprogramowaniu, zasadach SELinux lub w obu tych elementach.
Te komunikaty w dzienniku wskazują, które procesy nie powiodłyby się w trybie egzekwowania 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 te dane wyjściowe w ten sposób:
- Symbol
{ connectto }
powyżej oznacza podejmowane działanie. Wraz ztclass
na końcu (unix_stream_socket
) informuje, co mniej więcej zostało zrobione i w jakim celu. W tym przypadku coś próbowało połączyć się z gniazdem strumieniowym systemu Unix. - Ikona
scontext (u:r:shell:s0)
informuje, w jakim kontekście zainicjowano działanie. W tym przypadku jest to coś, co działa jako powłoka. - Symbol
tcontext (u:r:netd:s0)
informuje o kontekście celu działania. W tym przypadku jest to gniazdo unix_stream_socket należące do użytkownikanetd
. - Symbol
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 całkiem dobra wskazówka.
Inny przykład:
adb shell su root dmesg | grep 'avc: '
Urządzenie 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 – podjęte działanie jest wyróżnione w nawiasach, np.
read write
lubsetenforce
. - 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 wykonywana jest operacja, w tym przypadku kmem. - Wynik – wpis
tclass
(klasa docelowa) wskazuje typ obiektu, na którym wykonywana jest operacja, 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 przyczyny odmowy. Aby lepiej zrozumieć, dlaczego odmowa nastąpiła, warto zebrać łańcuch wywołań, w tym jądro i przestrzeń użytkownika.
W najnowszych wersjach jądra zdefiniowano punkt śledzenia o nazwie avc:selinux_audited
. Użyj Androidasimpleperf
, 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 lub nowszej, w szczególności gałęzie mainline i android12-5.10 wspólnego jądra Androida.
Obsługiwana jest też gałąź android12-5.4. Za pomocą
simpleperf
możesz sprawdzić, czy punkt śledzenia jest zdefiniowany na urządzeniu:adb root && adb shell simpleperf list | grep avc:selinux_audited
. W przypadku innych wersji jądra możesz wybrać poszczególne commity: dd81662 i 30969bc. - Powinno być możliwe odtworzenie wydarzenia, które debugujesz. Zdarzenia czasu rozruchu nie są obsługiwane w przypadku simpleperf, ale możesz ponownie uruchomić usługę, aby wywołać zdarzenie.
Przechwytywanie łańcucha wywołań
Pierwszym krokiem jest zarejestrowanie zdarzenia za pomocą funkcji 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 próbka powinna zostać zarejestrowana dzięki użyciu funkcji Ctrl-c
:
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
Na koniec możesz użyć simpleperf report
, aby sprawdzić przechwycony ś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. Zapewnia lepszy wgląd w przepływ kodu, ponieważ śledzenie rozpoczyna się w przestrzeni użytkownika i obejmuje całą ścieżkę aż do jądra, w którym następuje odmowa. Więcej informacji o simpleperf
znajdziesz w dokumentacji poleceń wykonywalnych Simpleperf.
Przełącz na licencję zezwalającą
Wymuszanie SELinux można wyłączyć za pomocą adb w przypadku kompilacji userdebug lub eng. Aby to zrobić, najpierw przełącz ADB na tryb root, wpisując adb root
. Następnie, aby wyłączyć egzekwowanie SELinux, uruchom to polecenie:
adb shell setenforce 0
lub w wierszu poleceń jądra (podczas wczesnego uruchamiania urządzenia):
androidboot.selinux=permissive
androidboot.selinux=enforcing
lub za pomocą bootconfig w Androidzie 12:
androidboot.selinux=permissive
androidboot.selinux=enforcing
Używanie narzędzia audit2allow
Narzędzie audit2allow
przyjmuje dmesg
odmowy i przekształca je w odpowiednie instrukcje zasad SELinux. Dzięki temu może znacznie przyspieszyć rozwój SELinux.
Aby go użyć, wpisz:
adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy
Należy jednak dokładnie sprawdzać każde potencjalne rozszerzenie pod kątem nadmiernych uprawnień. Na przykład podanie audit2allow
the
rmt_storage
denial pokazanego wcześniej spowoduje wyświetlenie tej sugerowanej instrukcji zasad SELinux:
#============= shell ============== allow shell kernel:security setenforce; #============= rmt ============== allow rmt kmem_device:chr_file { read write };
Dzięki temu rmt
zyskuje możliwość zapisywania pamięci jądra, co stanowi poważną lukę w zabezpieczeniach. Często audit2allow
oświadczenia są tylko punktem wyjścia. Po zastosowaniu tych stwierdzeń może być konieczne zmodyfikowanie domeny źródłowej i etykiety miejsca docelowego oraz włączenie odpowiednich makr, aby uzyskać prawidłowe zasady. Czasami odrzucenie, które jest sprawdzane, nie powinno w ogóle skutkować zmianami zasad. Zamiast tego należy zmienić aplikację, która narusza zasady.