SELinux jest skonfigurowany tak, aby domyślnie odrzucać dostęp, co oznacza, że każda próba dostępu, do której ma on hak w jądrze, musi być wyraźnie dozwolona przez zasady. Oznacza to, że plik zasad zawiera dużą ilość informacji o regułach, typach, klasach, uprawnieniach i innych elementach. Pełne omówienie SELinux wykracza poza zakres tego dokumentu, ale zrozumienie sposobu pisania reguł zasad jest teraz niezbędne przy wprowadzaniu nowych urządzeń z Androidem. W internecie można znaleźć wiele informacji na temat SELinux. Aby poznać sugerowane zasoby, zapoznaj się z dokumentacją pomocniczą.
Pliki kluczy
Aby włączyć SELinux, zintegruj najnowsze jądro Androida, a potem dodaj pliki znajdujące się w katalogu system/sepolicy. Po skompilowaniu te pliki stanowią politykę zabezpieczeń jądra SELinux i obsługują jądro systemu operacyjnego Android.
Ogólnie nie należy modyfikować plików system/sepolicy
bezpośrednio. Zamiast tego dodaj lub zmodyfikuj własne pliki zasad dotyczących urządzeń w katalogu /device/manufacturer/device-name/sepolicy
. W Androidzie 8.0 i nowszych zmiany wprowadzone w tych plikach powinny wpływać tylko na zasady w katalogu dostawców. Więcej informacji o oddzielaniu publicznych zasad SEPolicy w Androidzie 8.0 i nowszych znajdziesz w artykule Dostosowywanie zasad SEPolicy w Androidzie 8.0 i nowszych. Niezależnie od wersji Androida nadal modyfikujesz te pliki:
Pliki zasad
Pliki o nazwach kończących się na *.te
to pliki źródłowe zasad SELinux, które definiują domeny i ich etykiety. Może być konieczne utworzenie nowych plików zasad w /device/manufacturer/device-name/sepolicy
, ale w miarę możliwości należy spróbować zaktualizować istniejące pliki.
Pliki kontekstu
W plikach kontekstowych określasz etykiety obiektów.
file_contexts
przypisuje etykiety do plików i jest używany przez różne komponenty przestrzeni użytkownika. Podczas tworzenia nowych zasad utwórz lub zaktualizuj ten plik, aby przypisać nowe etykiety do plików. Aby zastosować nowefile_contexts
, ponownie utwórz obraz systemu plików lub uruchom polecenierestorecon
w pliku, którego etykiety chcesz zmienić. Podczas przekształcania zmiany wfile_contexts
są automatycznie stosowane do partycji systemowej i partycji danych użytkownika w ramach przekształcania. Zmiany można też automatycznie stosować podczas uaktualniania innych partycji, dodając do pliku init.board.rc wywołaniarestorecon_recursive
po zamontowaniu partycji do odczytu i zapisu.genfs_contexts
przypisuje etykiety do systemów plików, takich jakproc
lubvfat
, które nie obsługują rozszerzonych atrybutów. Ta konfiguracja jest wczytywana jako część zasad jądra, ale zmiany mogą nie zadziałać w przypadku inode w jądrze. Aby w pełni zastosować zmiany, konieczne może być ponowne uruchomienie systemu lub odmontowanie i ponowne zamontowanie systemu plików. Określone etykiety mogą być też przypisane do konkretnych uchwytów, takich jakvfat
, za pomocą opcjicontext=mount
.property_contexts
przypisuje etykiety właściwościom systemu Android, aby kontrolować, które procesy mogą je ustawiać. Ta konfiguracja jest odczytywana przez procesinit
podczas uruchamiania.service_contexts
przypisuje etykiety usługom bindera Androida, aby kontrolować, które procesy mogą dodawać (rejestrować) i znajdować (wyszukiwać) odwołanie do bindera dla usługi. Ta konfiguracja jest odczytywana przez processervicemanager
podczas uruchamiania.seapp_contexts
przypisuje etykiety do procesów aplikacji i katalogów/data/data
. Ta konfiguracja jest odczytywana przez proceszygote
przy każdym uruchomieniu aplikacji oraz przezinstalld
podczas uruchamiania.mac_permissions.xml
przypisuje tagseinfo
do aplikacji na podstawie ich sygnatury i opcjonalnie nazwy pakietu. Tagseinfo
można następnie wykorzystać jako klucz w plikuseapp_contexts
, aby przypisać określoną etykietę do wszystkich aplikacji z tym tagiemseinfo
. Ta konfiguracja jest odczytywana przezsystem_server
podczas uruchamiania.keystore2_key_contexts
przypisuje etykiety do przestrzeni nazw Keystore 2.0. Te przestrzenie nazw są wymuszane przez demona keystore2. Keystore zawsze udostępniał przestrzenie nazw oparte na identyfikatorach UID/AID. Keystore 2.0 dodatkowo wymusza przestrzenie nazw zdefiniowane w pliku sepolicy. Szczegółowy opis formatu i konwencji tego pliku znajdziesz tutaj.
BoardConfig.mk makefile
Po zmodyfikowaniu lub dodaniu plików zasad i kontekstu zaktualizuj plik /device/manufacturer/device-name/BoardConfig.mk
makefile, aby odwoływał się do podkatalogu sepolicy
i każdego nowego pliku zasad.
Więcej informacji o zmiennych BOARD_SEPOLICY
znajdziesz w
pliku system/sepolicy/README
.
BOARD_SEPOLICY_DIRS += \ <root>/device/manufacturer/device-name/sepolicy BOARD_SEPOLICY_UNION += \ genfs_contexts \ file_contexts \ sepolicy.te
Po przebudowaniu SELinux jest włączony na urządzeniu. Możesz teraz dostosować zasady SELinux, aby uwzględnić własne dodatki do systemu operacyjnego Android zgodnie z opisem w dostosowywaniu, lub zweryfikować istniejące ustawienia zgodnie z opisem w weryfikacji.
Gdy nowe pliki zasad i zmiany w pliku BoardConfig.mk zostaną zastosowane, nowe ustawienia zasad zostaną automatycznie wbudowane w końcowy plik zasad jądra. Więcej informacji o generowaniu pliku sepolicy na urządzeniu znajdziesz w artykule Generowanie pliku sepolicy.
Implementacja
Aby rozpocząć korzystanie z SELinux:
- Włącz SELinux w jądrze:
CONFIG_SECURITY_SELINUX=y
- Zmień parametr kernel_cmdline lub bootconfig tak, aby:
lubBOARD_KERNEL_CMDLINE := androidboot.selinux=permissive
To tylko wstępne opracowanie zasad dotyczących urządzenia. Gdy masz już początkową politykę bootstrap, usuń ten parametr, aby urządzenie stosowało tę politykę lub nie przechodziło CTS.BOARD_BOOTCONFIG := androidboot.selinux=permissive
- Uruchom system w trybie zezwalającym i sprawdź, jakie odmowy występują podczas uruchamiania:
W Ubuntu 14.04 lub nowszym: W Ubuntu 12.04:adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/BOARD/root/sepolicy
adb pull /sys/fs/selinux/policy adb logcat -b all | audit2allow -p policy
- Sprawdź, czy w wyniku nie występują ostrzeżenia podobne do
init: Warning! Service name needs a SELinux domain defined; please fix!
. Instrukcje i narzędzie do weryfikacji znajdziesz w artykule Weryfikacja. - Określanie urządzeń i innych nowych plików, które wymagają oznaczenia.
- Użyj istniejących lub nowych etykiet dla obiektów. Przejrzyj pliki
*_contexts
, aby sprawdzić, jak były wcześniej etykietowane, i przypisz nową etykietę, wiedząc, co oznaczają poszczególne etykiety. W idealnej sytuacji jest to istniejąca etykieta, która pasuje do zasad, ale czasami potrzebna jest nowa etykieta i reguły dostępu do niej. Dodaj etykiety do odpowiednich plików kontekstowych. - Określ domeny lub procesy, które powinny mieć własne domeny zabezpieczeń.
Prawdopodobnie musisz napisać dla każdej z nich zupełnie nowe zasady. Wszystkie usługi utworzone na podstawie usługi
init
powinny mieć własne nazwy. Te polecenia pomogą Ci znaleźć usługi, które nadal działają (ale WSZYSTKIE usługi wymagają takiej obsługi):
adb shell su -c ps -Z | grep init
adb shell su -c dmesg | grep 'avc: '
- Sprawdź
init.device.rc
, aby zidentyfikować domeny, które nie mają typu domeny. Podaj im domenę na wczesnym etapie procesu rozwoju, aby uniknąć dodawania reguł doinit
lub mylenia dostępówinit
z dostępami w ich własnych zasadach. - Aby używać zmiennych
BOARD_SEPOLICY_*
, skonfigurujBOARD_CONFIG.mk
. Szczegółowe informacje na temat konfigurowania tej funkcji znajdziesz w pliku README wsystem/sepolicy
. - Sprawdź pliki init.device.rc i fstab.device i upewnij się, że każde użycie opcji
mount
odpowiada poprawnie oznaczonemu systemowi plików lub że określono opcjęcontext= mount
. - Przejrzyj wszystkie odmowy i utwórz dla każdej z nich zasadę SELinux, aby odpowiednio je obsłużyć. Zobacz przykłady w sekcji Personalizacja.
Należy zacząć od zasad w AOSP, a następnie opracować własne dostosowywanie. Więcej informacji o strategii dotyczącej zasad i szczegóły dotyczące niektórych z tych kroków znajdziesz w artykule Tworzenie zasad SELinux.
Przykłady zastosowań
Oto konkretne przykłady exploitów, które warto wziąć pod uwagę podczas tworzenia własnego oprogramowania i powiązanych z nim zasad SELinux:
Symlinki: ponieważ wyglądają jak pliki, często są traktowane jako pliki, co może prowadzić do nadużyć. Na przykład niektóre komponenty uprzywilejowane, takie jak init
, zmieniają uprawnienia niektórych plików, czasami w nadmierny sposób.
Atakujący mogą wtedy zastąpić te pliki skrótami do kodu, nad którym mają kontrolę, co pozwoli im nadpisać dowolne pliki. Jeśli jednak wiesz, że Twoja aplikacja nigdy nie przechodzi przez link symboliczny, możesz zablokować jej to za pomocą SELinux.
Pliki systemowe: rozważ klasę plików systemowych, które powinny być modyfikowane tylko przez serwer systemowy. Ponieważ jednak netd
, init
i vold
działają jako root, mają dostęp do tych plików systemowych. Jeśli netd
zostanie naruszony, może to narazić te pliki i sam serwer systemowy.
Dzięki SELinux możesz zidentyfikować te pliki jako pliki danych serwera systemowego.
Dlatego jedyną domeną, która ma do nich dostęp do odczytu i zapisu, jest serwer systemowy.
Nawet jeśli netd
zostanie naruszony, nie będzie można przełączyć domen na domenę serwera systemowego i uzyskać dostępu do tych plików systemowych, mimo że działa on jako root.
Dane aplikacji: kolejnym przykładem jest klasa funkcji, które muszą działać jako root, ale nie powinny mieć dostępu do danych aplikacji. Jest to niezwykle przydatne, ponieważ można tworzyć różne twierdzenia, na przykład o tym, że niektóre domeny niezwiązane z danymi aplikacji mają zablokowany dostęp do internetu.
setattr: w przypadku poleceń takich jak chmod
i chown
możesz zidentyfikować zestaw plików, w których powiązana domena może wykonywać polecenie setattr
. Wszystko inne może być zabronione, nawet przez użytkownika root. Aplikacja może więc działać na podstawie reguł chmod
i chown
, ale nie shell_data_files
ani system_data_files
.app_data_files