Projekt Android Open Source (AOSP) zapewnia solidne zasady dotyczące aplikacji i usług, które są wspólne dla wszystkich urządzeń z Androidem. Uczestnicy projektu AOSP regularnie udoskonalają te zasady. Oczekuje się, że podstawowa zasada będzie stanowić 90–95% ostatecznej zasady na urządzeniu, a pozostałe 5–10% będą miały dostosowania specyficzne dla urządzeń. W tym artykule omawiamy te ustawienia, sposób tworzenia zasad dotyczących poszczególnych urządzeń oraz niektóre pułapki, których należy unikać.
Wprowadzanie urządzenia
Podczas tworzenia zasad dla konkretnego urządzenia wykonaj te czynności.
Uruchamianie w trybie mniej rygorystycznym
Gdy urządzenie jest w trybie zezwalającym, odmowy są rejestrowane, ale nie są egzekwowane. Tryb mniej rygorystyczny jest ważny z 2 powodów:
- Tryb zezwalający zapewnia, że wdrożenie zasad nie opóźnia innych zadań wdrożenia urządzenia.
- Wymuszone odrzucenie może maskować inne odrzucenia. Na przykład dostęp do plików obejmuje zwykle wyszukiwanie w katalogu, otwarcie pliku, a następnie jego odczytanie. W trybie egzekwowania zablokowane jest tylko wyszukiwanie w katalogu. Tryb zezwalający zapewnia, że wszystkie odmowy są widoczne.
Najprostszym sposobem przełączenia urządzenia w tryb permisywny jest użycie linii poleceń jądra. Można go dodać do pliku BoardConfig.mk
na urządzeniu:
platform/device/<vendor>/<target>/BoardConfig.mk
.
Po zmodyfikowaniu wiersza poleceń wykonaj polecenie make clean
, a następnie make bootimage
i sflashuj nowy obraz rozruchowy.
Następnie potwierdź tryb zezwalający:
adb shell getenforce
2 tygodnie to rozsądny czas, aby przejść do globalnego mniej rygorystycznego zachowania. Po rozwiązaniu większości problemów z odrzuceniami wróć do trybu egzekwowania i rozwiązuj błędy w miarę ich pojawiania się. Domeny, w których wciąż pojawiają się odmowy lub usługi, które są w trakcie intensywnego rozwoju, mogą zostać tymczasowo przełączone w tryb mniej rygorystyczny, ale jak najszybciej wrócić do trybu egzekwowania zasad.
Wymuś wcześniej
W trybie egzekwowania odmowy są zarówno rejestrowane, jak i egzekwowane. Najlepiej jak najszybciej ustawić urządzenie w trybie egzekwowania. Czekanie na utworzenie i wdrożenie zasad dotyczących konkretnych urządzeń często powoduje błędy w produkcie i niedogodności dla użytkowników. Zacznij wystarczająco wcześnie, aby móc wziąć udział w testach dogfooding i zapewnić pełne pokrycie testów funkcjonalności w rzeczywistym środowisku. Dzięki temu można wcześniej uwzględnić kwestie bezpieczeństwa w decyzjach projektowych. Z drugiej strony przyznawanie uprawnień wyłącznie na podstawie zaobserwowanych odmów jest niepewnym podejściem. Wykorzystaj ten czas na przeprowadzenie kontroli zabezpieczeń urządzenia i zgłoś błędy, jeśli nie chcesz, aby Twoje działania były dozwolone.
Usuwanie istniejącej zasady
Istnieje wiele powodów, dla których warto utworzyć zasady dotyczące konkretnego urządzenia od podstaw na nowym urządzeniu. Oto niektóre z nich:
- Kontrola bezpieczeństwa
- Zbyt mało restrykcyjne zasady
- Zmniejszenie rozmiaru zasad
- Zasady dotyczące treści przedstawiających śmierć
Rozwiązywanie problemów z odmową dostępu do usług podstawowych
Odmowy generowane przez usługi podstawowe są zwykle rozwiązywane przez etykietowanie plików. Na przykład:
avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0” dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1 avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1
jest całkowicie rozwiązany przez prawidłowe oznaczenie /dev/kgsl-3d0
. W tym przykładzie tcontext
to device
. Jest to kontekst domyślny, w którym wszystko w /dev
otrzymuje etykietę „
urządzenie”, chyba że zostanie przypisana bardziej szczegółowa etykieta. Po prostu zaakceptowanie danych wyjściowych z audit2allow spowoduje nieprawidłową regułę zbyt mało restrykcyjną.
Aby rozwiązać ten problem, nadaj plikowi bardziej szczegółową etykietę, w tym przypadku gpu_device. Nie są potrzebne żadne dodatkowe uprawnienia, ponieważ mediaserver ma już niezbędne uprawnienia w podstawowych zasadach dostępu do gpu_device.
Inne pliki przeznaczone na konkretne urządzenia, które powinny być oznaczone etykietami z użyciem typów zdefiniowanych w podstawowych zasadach:
- blokowanie urządzeń
- urządzenia audio
- urządzenia do odtwarzania filmów
- czujniki
- nfc
- urządzenie_gps
- pliki w /sys
- pliki w /proc
Generalnie przyznawanie uprawnień do domyślnych etykiet jest nieprawidłowe. Wiele z tych uprawnień jest niedozwolonych z powodu reguł neverallow, ale nawet wtedy, gdy nie ma wyraźnego zakazu, zalecamy dodanie odpowiedniej etykiety.
Oznaczaj nowe usługi etykietami i odmowa adresów
Uruchomione w ten sposób usługi muszą działać we własnych domenach SELinux. Poniższy przykład umieszcza usługę „foo” w własnej domenie SELinux i przyznaje jej uprawnienia.
Usługa jest uruchamiana w pliku init.device.rc
na urządzeniu jako:
service foo /system/bin/foo class core
- Utwórz nową domenę „foo”
Utwórz plik
device/manufacturer/device-name/sepolicy/foo.te
z tą zawartością:# foo service type foo, domain; type foo_exec, exec_type, file_type; init_daemon_domain(foo)
To jest początkowy szablon domeny foo SELinux, do którego możesz dodawać reguły na podstawie konkretnych operacji wykonywanych przez plik wykonywalny.
- Etykieta
/system/bin/foo
Dodaj te informacje do pliku
device/manufacturer/device-name/sepolicy/file_contexts
:/system/bin/foo u:object_r:foo_exec:s0
Dzięki temu plik wykonywalny jest odpowiednio oznaczony, aby SELinux mógł uruchomić usługę w odpowiedniej domenie.
- Utwórz i sflashuj obrazy rozruchowy i systemowy.
- Sprecyzuj reguły SELinux.
Na podstawie odrzuceń określ wymagane uprawnienia. Narzędzie audit2allow zawiera dobre wskazówki, ale używaj go tylko do tworzenia zasad. Nie kopiuj tylko danych wyjściowych.
Powrót do trybu egzekwowania
Rozwiązywanie problemów w trybie zezwalającym jest w porządku, ale jak najszybciej wróć do trybu egzekwowania i staraj się w nim pozostawać.
Typowe błędy
Oto kilka rozwiązań typowych błędów popełnianych podczas tworzenia zasad dotyczących konkretnych urządzeń.
Nadużywanie negacji
Przykładowa reguła poniżej wygląda, jak zamykanie drzwi frontowych i pozostawanie otwartych okien:
allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms
Zamysł jest jasny: dostęp do urządzenia do debugowania mają wszyscy oprócz aplikacji innych firm.
Reguła ma kilka wad. Wykluczenie domeny untrusted_app
jest proste, ponieważ wszystkie aplikacje mogą opcjonalnie uruchamiać usługi w domenie isolated_app
. Podobnie, jeśli do AOSP zostaną dodane nowe domeny aplikacji innych firm, będą one miały dostęp do scary_debug_device
.
Reguła jest zbyt mało restrykcyjna. Większość domen nie skorzysta z dostępu do tego narzędzia do debugowania. Reguła powinna zezwalać tylko na domeny, które wymagają dostępu.
Funkcje debugowania w wersji produkcyjnej
Funkcje debugowania nie powinny znajdować się w wersjach produkcyjnych ani w zasadach.
Najprostszą alternatywą jest zezwolenie na funkcję debugowania tylko wtedy, gdy SELinux jest wyłączony w kompilacji eng/userdebug, np. adb root
i adb shell setenforce 0
.
Innym bezpiecznym rozwiązaniem jest umieszczenie uprawnień do debugowania w instrukcji userdebug_or_eng.
Wybuch rozmiaru zasad
Characterizing SEAndroid Policies in the Wild opisuje niepokojący trend wzrostu liczby dostosowań zasad dotyczących urządzeń. Zasady dotyczące poszczególnych urządzeń powinny stanowić 5–10% wszystkich zasad działających na urządzeniu. Niestandardowe rozwiązania, które zajmują ponad 20%czasu, z całą pewnością zawierają zbyt wiele uprzywilejowanych domen i nieaktualnych zasad.
Zbyt duża zasada:
- Wymaga podwójnego dostępu do pamięci, ponieważ polityka znajduje się w pamięci RAM i jest również ładowana do pamięci jądra.
- Zajmuje miejsce na dysku, ponieważ wymaga większego obrazu rozruchowego.
- Wpływa na czas wyszukiwania zasady środowiska wykonawczego.
Ten przykład pokazuje 2 urządzenia, na których zasady producenta stanowią 50% i 40% zasad na urządzeniu. Przepisanie zasad przyniosło znaczne ulepszenia zabezpieczeń bez utraty funkcjonalności, jak pokazano poniżej. (urządzenia AOSP Shamu i Flounder są uwzględnione w celu porównania).
W obu przypadkach zasady zostały znacznie skrócone pod względem rozmiaru i liczby uprawnień. Zmniejszenie rozmiaru zasad jest prawie całkowicie spowodowane usunięciem zbędących uprawnień, z których wiele było prawdopodobnie regułami wygenerowanymi przez audit2allow
, które zostały bezkrytycznie dodane do zasad. Na obu urządzeniach problemem były też martwe domeny.
Przyznaj funkcję dac_override
Odmowa dac_override
oznacza, że proces, który ją wywołał, próbuje uzyskać dostęp do pliku z nieprawidłowymi uprawnieniami użytkownika/grupy/świata Unix.
Właściwym rozwiązaniem prawie nigdy nie jest przyznanie uprawnienia dac_override
.
Zamiast tego
zmieniaj uprawnienia Unixa do pliku lub procesu. Niektóre domeny, takie jak init
, vold
i installd
, naprawdę potrzebują możliwości zastąpienia uprawnień plików Unix do dostępu do plików innych procesów.
Więcej informacji znajdziesz na blogu Dana Walsha.