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. Zasady podstawowe powinny stanowić około 90–95% ostatecznych zasad na urządzeniu, a dostosowania na potrzeby konkretnego urządzenia – pozostałe 5–10%. 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 dotyczących poszczególnych urządzeń 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 wczesnych zadań związanych z wdrażaniem urządzenia.
- Wymuszone odrzucenie może maskować inne odrzucenia. Na przykład dostęp do pliku zwykle obejmuje wyszukiwanie w katalogu, otwieranie pliku, a następnie odczyt pliku. 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 flashuj nowy obraz rozruchowy.
Następnie potwierdź tryb zezwalający:
adb shell getenforce
2 tygodnie to odpowiedni czas na korzystanie z globalnego trybu zezwalającego. 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, które nadal powodują odmowy lub usługi, które są w intensywnym rozwoju, mogą zostać tymczasowo przełączone w tryb zezwalający, ale należy jak najszybciej przywrócić je do trybu egzekwowania.
Wymuś wcześniej
W trybie egzekwowania odmowy są rejestrowane 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 wziąć udział w testach dogfooding i zapewnić pełne pokrycie testów funkcjonalności w rzeczywistych warunkach. Dzięki temu, że zaczniesz wcześnie, będziesz mieć pewność, że decyzje projektowe będą uwzględniać kwestie bezpieczeństwa. Z drugiej strony przyznawanie uprawnień wyłącznie na podstawie zaobserwowanych odmów jest niepewnym podejściem. Wykorzystaj ten czas na przeprowadzenie kontroli bezpieczeństwa urządzenia i zgłaszanie błędów związanych z zachowaniem, które nie powinno być 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
- Zmniejszanie 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. 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 etykietą /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ę, która w tym przypadku to 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 związane z urządzeniem, które powinny być oznaczone typami zdefiniowanymi w podstawowych zasadach:
- blokowanie urządzeń
- urządzenia audio
- urządzenia do odtwarzania filmów
- czujniki
- nfc
- gps_device
- pliki w katalogu /sys
- pliki w katalogu /proc
Generalnie przyznawanie uprawnień do domyślnych etykiet jest nieprawidłowe. Wiele z tych uprawnień jest zabronionych przez reguły neverallow, ale nawet wtedy, gdy nie są wyraźnie zabronione, zalecamy dodanie odpowiedniej etykiety.
Oznaczanie nowych usług i adresów odmów
Usługi uruchamiane przez init muszą działać w ramach własnych domen SELinux. W tym przykładzie usługa „foo” jest umieszczana w swojej własnej domenie SELinux i przyznawane są 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
o tej treści:# foo service type foo, domain; type foo_exec, exec_type, file_type; init_daemon_domain(foo)
To początkowy szablon domeny SELinux foo, do której 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.
- Doprecyzuj reguły SELinux w domenie.
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 poszczególnych urządzeń.
nadmierne używanie negacji,
Przykładowa reguła poniżej jest jak zamykanie drzwi wejściowych, ale pozostawienie 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 zawiera kilka błędów. 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.
Debugowanie funkcji w środowisku produkcyjnym
Funkcje debugowania nie powinny znajdować się w wersjach produkcyjnych ani w zasadach.
Najprostszą alternatywą jest zezwolenie na debugowanie tylko wtedy, gdy SELinux jest wyłączony w kompilacji eng/userdebug, np. adb root
i adb shell setenforce 0
.
Inną bezpieczną alternatywą jest umieszczenie uprawnień 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 dają wynik powyżej 20%, z całą pewnością zawierają nadmiernie uprzywilejowane domeny i nieaktualne zasady.
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 zasad w czasie wykonywania.
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 w zakresie zabezpieczeń bez utraty funkcjonalności, jak pokazano poniżej. (urządzenia AOSP Shamu i Flounder są uwzględnione w celu porównania).
Rysunek 1 Porównanie rozmiaru zasad dotyczących poszczególnych urządzeń po sprawdzeniu bezpieczeństwa.
W obu przypadkach zasady zostały znacznie skrócone pod względem rozmiaru i liczby uprawnień. Zmniejszenie rozmiaru zasad jest spowodowane prawie wyłącznie 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.
Przyznawanie możliwości 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.
Prawidłowe rozwiązanie polega na tym, aby prawie nigdy nie przyznawać uprawnienia dac_override
.
Zamiast tego
zmieniaj uprawnienia Unixa dotyczące 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.