Projekt Android Open Source Project (AOSP) zapewnia solidną podstawę zasad dla aplikacji i usług wspólnych dla wszystkich urządzeń z systemem Android. Współpracownicy AOSP regularnie udoskonalają tę politykę. Oczekuje się, że podstawowe zasady będą stanowić około 90–95% ostatecznych zasad obowiązujących na urządzeniu, a dostosowania specyficzne dla urządzenia będą stanowić pozostałe 5–10%. W tym artykule skupiono się na dostosowaniach specyficznych dla urządzenia, sposobie pisania zasad dla poszczególnych urządzeń oraz niektórych pułapkach, których należy unikać.
Przywołanie urządzenia
Pisząc zasady specyficzne dla urządzenia, wykonaj następujące kroki.
Uruchom w trybie zezwalającym
Gdy urządzenie znajduje się w trybie zezwalającym , odmowy są rejestrowane, ale nie są wymuszane. Tryb zezwalający jest ważny z dwóch powodów:
- Tryb zezwalający zapewnia, że uruchomienie zasad nie opóźnia innych zadań związanych z wczesnym uruchamianiem urządzenia.
- Wymuszona odmowa może maskować inne odmowy. Na przykład dostęp do pliku zazwyczaj obejmuje przeszukanie katalogu, otwarcie pliku, a następnie odczytanie pliku. W trybie wymuszania wystąpiłaby jedynie odmowa wyszukiwania w katalogu. Tryb zezwalający zapewnia, że wszystkie odmowy będą widoczne.
Najprostszym sposobem przełączenia urządzenia w tryb zezwalający jest użycie wiersza poleceń jądra . Można to dodać do pliku BoardConfig.mk
urządzenia: platform/device/<vendor>/<target>/BoardConfig.mk
. Po zmodyfikowaniu wiersza poleceń wykonaj make clean
, następnie make bootimage
i flashuj nowy obraz startowy.
Następnie potwierdź tryb zezwalający za pomocą:
adb shell getenforce
Dwa tygodnie to rozsądna ilość czasu, aby działać w globalnym trybie zezwalającym. Po rozwiązaniu większości odmów wróć do trybu wymuszania i usuwaj pojawiające się błędy. Domeny nadal generujące odmowy lub usługi będące w fazie intensywnego rozwoju można tymczasowo przełączyć w tryb zezwalający, ale jak najszybciej przenieś je z powrotem do trybu wymuszania.
Egzekwuj wcześnie
W trybie wymuszania odmowy są rejestrowane i egzekwowane. Najlepszą praktyką jest jak najwcześniejsze przełączenie urządzenia w tryb wymuszania. Oczekiwanie na utworzenie i egzekwowanie zasad dotyczących konkretnego urządzenia często skutkuje błędami produktu i złym doświadczeniem użytkownika. Rozpocznij wystarczająco wcześnie, aby wziąć udział w testowaniu funkcjonalności i zapewnić pełny zakres testów funkcjonalności w rzeczywistym użytkowaniu. Wczesne rozpoczęcie pracy gwarantuje, że kwestie bezpieczeństwa będą miały wpływ na decyzje projektowe. Z drugiej strony przyznawanie uprawnień wyłącznie na podstawie zaobserwowanych odmów jest podejściem niebezpiecznym. Wykorzystaj ten czas na przeprowadzenie audytu bezpieczeństwa urządzenia i zgłoszenie błędów dotyczących zachowań, które nie powinny być dozwolone.
Usuń lub usuń istniejącą politykę
Istnieje wiele dobrych powodów, dla których warto utworzyć od podstaw zasady dotyczące konkretnego urządzenia na nowym urządzeniu, między innymi:
- Audyt bezpieczeństwa
- Zbyt liberalna polityka
- Zmniejszenie rozmiaru polityki
- Martwa polityka
Rozwiązanie problemu odmów świadczenia usług podstawowych
Odmowy generowane przez usługi podstawowe są zwykle rozwiązywane poprzez 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
zostało całkowicie rozwiązane poprzez odpowiednie oznaczenie /dev/kgsl-3d0
. W tym przykładzie tcontext
to device
. Reprezentuje to domyślny kontekst, w którym wszystko w /dev
otrzymuje etykietę „ urządzenie ”, chyba że przypisano bardziej szczegółową etykietę. Samo zaakceptowanie danych wyjściowych z audytu2allow tutaj spowodowałoby niepoprawną i nadmiernie liberalną regułę.
Aby rozwiązać tego rodzaju problem, nadaj plikowi bardziej szczegółową etykietę, która w tym przypadku to gpu_device . Żadne dalsze uprawnienia nie są potrzebne, ponieważ serwer multimediów ma już niezbędne uprawnienia w zasadach podstawowych, aby uzyskać dostęp do urządzenia gpu.
Inne pliki specyficzne dla urządzenia, które powinny być oznaczone typami predefiniowanymi w zasadach podstawowych:
- blokować urządzenia
- urządzenia audio
- urządzenia wideo
- czujniki
- NFC
- urządzenie_gps
- pliki w /sys
- pliki w /proc
Ogólnie rzecz biorąc, nadawanie uprawnień domyślnym etykietom jest błędne. Wiele z tych uprawnień jest zabronionych przez reguły Neverallow , ale nawet jeśli nie są one wyraźnie zabronione, najlepszą praktyką jest zapewnienie określonej etykiety.
Oznacz nowe usługi i adresuj odmowy
Usługi uruchamiane przez Init muszą działać we własnych domenach SELinux. Poniższy przykład umieszcza usługę „foo” w jej własnej domenie SELinux i przyznaje jej uprawnienia.
Usługa uruchamia się w init. device .rc
jako:
service foo /system/bin/foo class core
- Utwórz nową domenę „foo”
Utwórz plik
device/ manufacturer / device-name /sepolicy/foo.te
z następującą zawartością:# foo service type foo, domain; type foo_exec, exec_type, file_type; init_daemon_domain(foo)
Jest to początkowy szablon domeny foo SELinux, do którego można dodawać reguły oparte na konkretnych operacjach wykonywanych przez ten plik wykonywalny.
- Etykieta
/system/bin/foo
Dodaj następujące polecenie do
device/ manufacturer / device-name /sepolicy/file_contexts
:/system/bin/foo u:object_r:foo_exec:s0
Dzięki temu plik wykonywalny jest odpowiednio oznaczony, dzięki czemu SELinux uruchamia usługę w odpowiedniej domenie.
- Zbuduj i flashuj obrazy rozruchowe i systemowe.
- Udoskonal reguły SELinux dla domeny.
Użyj odmów, aby określić wymagane uprawnienia. Narzędzie audyt2allow zapewnia dobre wytyczne, ale używaj go wyłącznie do celów tworzenia polityki. Nie kopiuj tylko wyników.
Przełącz z powrotem do trybu wymuszania
Rozwiązywanie problemów w trybie zezwalającym jest w porządku, ale jak najszybciej przełącz się z powrotem do trybu wymuszania i staraj się w nim pozostać.
Typowe błędy
Oto kilka rozwiązań typowych błędów, które zdarzają się podczas pisania zasad dotyczących konkretnych urządzeń.
Nadużywanie negacji
Następująca przykładowa zasada przypomina zamykanie drzwi wejściowych i pozostawienie otwartych okien:
allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms
Intencja jest jasna: dostęp do urządzenia debugującego mogą mieć wszyscy oprócz aplikacji innych firm.
Przepis jest wadliwy pod kilkoma względami. Wyłączenie untrusted_app
jest proste do obejścia, ponieważ wszystkie aplikacje mogą opcjonalnie uruchamiać usługi w domenie isolated_app
. Podobnie, jeśli do AOSP zostaną dodane nowe domeny dla aplikacji innych firm, będą one również miały dostęp do scary_debug_device
. Przepis jest zbyt liberalny. Większość domen nie odniesie korzyści z dostępu do tego narzędzia do debugowania. Reguła powinna zostać napisana tak, aby zezwalała tylko na domeny wymagające dostępu.
Debugowanie funkcji w środowisku produkcyjnym
Funkcje debugowania nie powinny być obecne w kompilacjach produkcyjnych ani nie powinny być obecne w ich zasadach.
Najprostszą alternatywą jest zezwolenie na funkcję debugowania tylko wtedy, gdy SELinux jest wyłączony w kompilacjach eng/userdebug, takich jak adb root
i adb shell setenforce 0
.
Inną bezpieczną alternatywą jest zawarcie uprawnień do debugowania w instrukcji userdebug_or_eng .
Eksplozja rozmiarów polityki
Charakterystyka zasad SEAndroid in the Wild opisuje niepokojący trend w zakresie dostosowywania zasad dotyczących urządzeń. Zasady specyficzne dla urządzenia powinny stanowić 5–10% ogólnej polityki działającej na urządzeniu. Dostosowania w zakresie 20%+ prawie na pewno zawierają domeny nadmiernie uprzywilejowane i martwe zasady.
Niepotrzebnie duża polityka:
- Podwójnie obciąża pamięć, ponieważ polityka znajduje się w ramdysku i jest również ładowana do pamięci jądra.
- Marnuje miejsce na dysku, wymagając większego obrazu rozruchowego.
- Wpływa na czas wyszukiwania zasad środowiska wykonawczego.
Poniższy przykład pokazuje dwa urządzenia, w przypadku których zasady specyficzne dla producenta stanowią 50% i 40% zasad obowiązujących na urządzeniu. Przepisanie zasad przyniosło znaczną poprawę bezpieczeństwa bez utraty funkcjonalności, jak pokazano poniżej. (W celach porównawczych dołączono urządzenia AOSP Shamu i Flounder.)
Rysunek 1 . Porównanie rozmiaru zasad specyficznych dla urządzenia po audycie bezpieczeństwa.
W obu przypadkach polityka została radykalnie zmniejszona zarówno pod względem rozmiaru, jak i liczby uprawnień. Zmniejszenie rozmiaru polityki jest prawie całkowicie spowodowane usunięciem niepotrzebnych uprawnień, z których wiele to prawdopodobnie reguły wygenerowane przez audit2allow
, które zostały bezkrytycznie dodane do polityki. Martwe domeny również stanowiły problem w przypadku obu urządzeń.
Przyznanie możliwości dac_override
Odmowa dac_override
oznacza, że proces powodujący naruszenie próbuje uzyskać dostęp do pliku z nieprawidłowymi uprawnieniami użytkownika/grupy/świata systemu UNIX. Właściwym rozwiązaniem prawie nigdy nie jest przyznanie uprawnienia dac_override
. Zamiast tego zmień uprawnienia Unix do pliku lub procesu . Kilka domen, takich jak init
, vold
i installd
naprawdę potrzebuje możliwości nadpisywania uprawnień do plików uniksowych, aby uzyskać dostęp do plików innych procesów. Bardziej szczegółowe wyjaśnienia można znaleźć na blogu Dana Walsha .