Android zdecydowanie zachęca producentów OEM do dokładnego testowania swoich implementacji SELinux. Ponieważ producenci wdrażają SELinux, powinni najpierw zastosować nową politykę do puli testowej urządzeń.
Po zastosowaniu nowej polityki upewnij się, że SELinux działa na urządzeniu we właściwym trybie, wydając polecenie getenforce
.
Spowoduje to wydrukowanie globalnego trybu SELinux: wymuszającego lub zezwalającego. Aby określić tryb SELinux dla każdej domeny, musisz sprawdzić odpowiednie pliki lub uruchomić najnowszą wersję sepolicy-analyze
z odpowiednią flagą ( -p
), znajdującą się w /platform/system/sepolicy/tools/
.
Czytanie zaprzeczeń
Sprawdź błędy, które są kierowane jako dzienniki zdarzeń do dmesg
i logcat
i można je przeglądać lokalnie na urządzeniu. Producenci powinni sprawdzić dane wyjściowe SELinux wysyłane do dmesg
na tych urządzeniach i dopracować ustawienia przed publicznym udostępnieniem w trybie zezwalającym i ewentualnym przejściem na tryb wymuszający. Komunikaty dziennika SELinux zawierają avc:
i dlatego można je łatwo znaleźć za pomocą grep
. Możliwe jest przechwycenie bieżących dzienników odmów poprzez uruchomienie cat /proc/kmsg
lub przechwycenie dzienników odmów z poprzedniego rozruchu poprzez uruchomienie cat /sys/fs/pstore/console-ramoops
.
Komunikaty o błędach SELinux są ograniczone po zakończeniu rozruchu, aby uniknąć zaśmiecania dzienników. Aby mieć pewność, że widzisz wszystkie odpowiednie komunikaty, możesz to wyłączyć, uruchamiając adb shell auditctl -r 0
.
Dzięki tym wynikom producenci mogą łatwo zidentyfikować, kiedy użytkownicy systemu lub komponenty naruszają zasady SELinux. Producenci mogą następnie naprawić to złe zachowanie, zmieniając oprogramowanie, zasady SELinux lub jedno i drugie.
W szczególności te komunikaty dziennika wskazują, które procesy zawiodą 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 następujący sposób:
- Powyższy element
{ connectto }
reprezentuje podejmowane działanie. Razem ztclass
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 strumieniowym Unix. -
scontext (u:r:shell:s0)
informuje, 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 donetd
. -
comm="ping"
na górze daje dodatkową wskazówkę na temat tego, co było wykonywane w momencie wygenerowania odmowy. W tym przypadku jest to całkiem niezła podpowiedź.
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 tej odmowy:
- Akcja - próba akcji jest podświetlona w nawiasach,
read write
lubsetenforce
. - Aktor — wpis
scontext
(kontekst źródłowy) reprezentuje aktora, 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 przypadku plikchr_file
(urządzenie znakowe).
Zrzucanie stosów użytkowników i jądra
W niektórych przypadkach informacje zawarte w dzienniku zdarzeń nie są wystarczające do ustalenia ź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 nastąpiła odmowa.
Najnowsze jądra definiują punkt śledzenia o nazwie avc:selinux_audited
. Użyj simpleperf
Android, aby włączyć ten punkt śledzenia i przechwycić łańcuch połączeń.
Obsługiwana konfiguracja
- Obsługiwane jest jądro Linuksa >= 5.10, w szczególności obsługiwane są główne gałęzie Android Common Kernel i Android 12-5.10 . Obsługiwana jest także gałąź Android12-5.4 . Możesz użyć
simpleperf
, aby określić, czy na Twoim urządzeniu zdefiniowano punkt śledzenia:adb root && adb shell simpleperf list | grep avc:selinux_audited
. W przypadku innych wersji jądra możesz wybrać zatwierdzenia dd81662 i 30969bc . - Powinno być możliwe odtworzenie debugowanego zdarzenia. Zdarzenia czasu rozruchu nie są obsługiwane przy użyciu Simpleperf; jednak nadal możesz być w stanie ponownie uruchomić usługę, aby wywołać zdarzenie.
Przechwytywanie łańcucha połączeń
Pierwszym krokiem jest nagranie zdarzenia przy użyciu 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 należy zatrzymać nagrywanie. W tym przykładzie, używając Ctrl-c
, próbka powinna zostać przechwycona:
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
Wreszcie simpleperf report
może zostać 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 wgląd w przepływ kodu, rozpoczynając śledzenie od przestrzeni użytkownika aż do jądra, gdzie następuje odmowa. Więcej informacji na temat simpleperf
można znaleźć w dokumentacji dotyczącej poleceń wykonywalnych Simpleperf
Przełączam na permisywne
Wymuszanie SELinux można wyłączyć za pomocą ADB w przypadku debugowania użytkownika lub kompilacji 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 poprzez bootconfig w Androidzie 12:
androidboot.selinux=permissive
androidboot.selinux=enforcing
Korzystanie z audytu2allow
Narzędzie audit2allow
pobiera odmowy dmesg
i konwertuje je na odpowiednie instrukcje polityki SELinux. Jako taki może znacznie przyspieszyć rozwój SELinuksa.
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ść i sprawdzić każdy potencjalny dodatek pod kątem nadmiernych uprawnień. Na przykład, karmienie audit2allow
odmowę rmt_storage
pokazaną wcześniej, skutkuje następującym sugerowanym oświadczeniem polityki SELinux:
#============= shell ============== allow shell kernel:security setenforce; #============= rmt ============== allow rmt kmem_device:chr_file { read write };
Zapewniłoby to rmt
możliwość zapisywania pamięci jądra, co stanowi rażącą lukę w zabezpieczeniach. Często instrukcje audit2allow
stanowią jedynie punkt wyjścia. Po zastosowaniu tych instrukcji może zaistnieć potrzeba zmiany domeny źródłowej i etykiety celu, a także włączenia odpowiednich makr, aby uzyskać dobrą politykę. Czasami badana odmowa nie powinna w ogóle skutkować żadnymi zmianami polityki; należy raczej zmienić aplikację powodującą naruszenie.