SELinux jest skonfigurowany tak, aby domyślnie odmawiać dostępu. Oznacza to, że każdy dostęp, do którego ma dostęp w jądrze, musi być wyraźnie dozwolony przez zasady. Oznacza to, że plik zasad zawiera dużą ilość informacji dotyczących reguł, typów, klas, uprawnień i innych elementów. Pełne omówienie SELinux wykracza poza zakres tego dokumentu, ale zrozumienie sposobu pisania reguł zasad jest teraz niezbędne podczas uruchamiania nowych urządzeń z Androidem. Dostępnych jest już wiele informacji na temat SELinux. Więcej informacji znajdziesz w sekcji Dokumenty uzupełniające.
Kluczowe pliki
Aby włączyć SELinux, zintegruj najnowsze jądro Androida, a następnie włącz pliki znajdujące się w katalogu system/sepolicy. Po skompilowaniu te pliki tworzą zasady zabezpieczeń jądra SELinux i obejmują system operacyjny Android w wersji upstream.
Ogólnie rzecz biorąc, nie należy bezpośrednio modyfikować plików system/sepolicy
. Zamiast tego dodaj lub edytuj własne pliki zasad dotyczące konkretnych urządzeń w katalogu/device/manufacturer/device-name/sepolicy
. W Androidzie 8.0 i nowszych zmiany wprowadzane w tych plikach powinny wpływać tylko na zasady w katalogu dostawcy. Więcej informacji o rozdzieleniu publicznych zasad SEPolicy w Androidzie 8.0 i nowszym znajdziesz w artykule Dostosowywanie zasad SEPolicy w Androidzie 8.0 i nowszym. Niezależnie od wersji Androida nadal modyfikujesz te pliki:
Pliki zasad
Pliki kończące się na *.te
to pliki źródłowe zasad SELinux, które określają 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 aktualizować 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 skompiluj obraz systemu plików lub uruchomrestorecon
w pliku, który ma zostać ponownie oznaczony. Podczas uaktualniania zmiany wfile_contexts
są automatycznie stosowane do partycji systemowej i partycji danych użytkownika w ramach uaktualniania. Zmiany można też zastosować automatycznie podczas uaktualniania do innych partycji, dodając wywołaniarestorecon_recursive
do pliku initboard.rc po zamontowaniu partycji w trybie odczytu i zapisu.genfs_contexts
przypisuje etykiety do systemów plików, takich jakproc
lubvfat
, które nie obsługują atrybutów rozszerzonych. Ta konfiguracja jest wczytywana w ramach zasad jądra, ale zmiany mogą nie zostać zastosowane w przypadku węzłów inode w jądrze. Aby w pełni zastosować zmianę, konieczne może być ponowne uruchomienie urządzenia lub odmontowanie i ponowne zamontowanie systemu plików. Do konkretnych uchwytów można też przypisać określone etykiety, np.vfat
za pomocą opcjicontext=mount
.property_contexts
przypisuje etykiety do właściwości systemu Android, aby kontrolować, które procesy mogą je ustawiać. Ta konfiguracja jest odczytywana przez procesinit
podczas uruchamiania.service_contexts
przypisuje etykiety do usług Android Binder, aby kontrolować, które procesy mogą dodawać (rejestrować) i znajdować (wyszukiwać) odwołanie do usługi Binder. Ta konfiguracja jest odczytywana przez processervicemanager
podczas uruchamiania.seapp_contexts
przypisuje etykiety do procesów aplikacji i/data/data
katalogów. Ta konfiguracja jest odczytywana przez proceszygote
przy każdym uruchomieniu aplikacji i przezinstalld
podczas uruchamiania.mac_permissions.xml
przypisuje do aplikacji tagseinfo
na podstawie ich podpisu i opcjonalnie nazwy pakietu. Tagseinfo
może być używany jako klucz w plikuseapp_contexts
do przypisywania określonej etykiety do wszystkich aplikacji z tym tagiemseinfo
. Ta konfiguracja jest odczytywana przezsystem_server
podczas uruchamiania.keystore2_key_contexts
przypisuje etykiety do przestrzeni nazw Keystore 2. Te przestrzenie nazw są wymuszane przez demonakeystore2
. Keystore zawsze udostępniał przestrzenie nazw oparte na identyfikatorach UID/AID. Keystore 2 dodatkowo wymusza przestrzenie nazw zdefiniowane przez sepolicy. Szczegółowy opis formatu i konwencji tego pliku znajdziesz tutaj.
Plik BoardConfig.mk
Po edytowaniu lub dodaniu plików zasad i kontekstu zaktualizuj plik makefile, aby odwoływał się do podkatalogu sepolicy
i każdego nowego pliku zasad./device/manufacturer/device-name/BoardConfig.mk
Więcej informacji o zmiennych BOARD_SEPOLICY
znajdziesz w
system/sepolicy/README
.
BOARD_SEPOLICY_DIRS += \ <root>/device/manufacturer/device-name/sepolicy BOARD_SEPOLICY_UNION += \ genfs_contexts \ file_contexts \ sepolicy.te
Po ponownym utworzeniu urządzenie będzie miało włączony SELinux. Możesz teraz dostosować zasady SELinux, aby uwzględnić własne dodatki do systemu operacyjnego Android, zgodnie z opisem w sekcji Dostosowywanie, lub zweryfikować istniejącą konfigurację zgodnie z opisem w sekcji Weryfikacja.
Gdy nowe pliki zasad i aktualizacje BoardConfig.mk zostaną wprowadzone, nowe ustawienia zasad zostaną automatycznie wbudowane w końcowy plik zasad jądra. Więcej informacji o tym, jak sepolicy jest tworzony na urządzeniu, znajdziesz w artykule Tworzenie 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
Dotyczy to tylko początkowego opracowywania zasad dotyczących urządzenia. Gdy będziesz mieć początkową zasadę rozruchu, usuń ten parametr, aby urządzenie wymuszało zgodność z CTS lub nie przeszło testu.BOARD_BOOTCONFIG := androidboot.selinux=permissive
- Uruchom system w trybie zezwalającym i sprawdź, jakie odmowy wystąpią podczas uruchamiania:
W Ubuntu 14.04 lub nowszym: 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 odpowiedzi nie ma ostrzeżeń podobnych do tego:
init: Warning! Service name needs a SELinux domain defined; please fix!
Instrukcje i narzędzia znajdziesz w sekcji Weryfikacja. - identyfikować urządzenia i inne nowe pliki, które wymagają etykietowania;
- Używaj istniejących lub nowych etykiet obiektów. Sprawdź
*_contexts
pliki, aby zobaczyć, jak wcześniej oznaczano treści, i wykorzystaj wiedzę o znaczeniu etykiet, aby przypisać nową. Najlepiej, aby była 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ć zupełnie nowe zasady dla każdego z nich. Wszystkie usługi utworzone na podstawie
init
powinny mieć własne. Te polecenia pomagają wykryć usługi, które nadal działają (ale WSZYSTKIE usługi wymagają takiego traktowania):
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. Nadaj im domenę na wczesnym etapie procesu tworzenia, aby uniknąć dodawania reguł doinit
lub w inny sposób mylenia dostępu doinit
z dostępem do własnych zasad. - Skonfiguruj
BOARD_CONFIG.mk
, aby używać zmiennychBOARD_SEPOLICY_*
. Szczegółowe informacje o konfigurowaniu tej funkcji znajdziesz w pliku README wsystem/sepolicy
. - Sprawdź pliki init.device.rc i fstab.device i upewnij się, że każde użycie
mount
odpowiada prawidłowo oznaczonemu systemowi plików lub że określono opcjęcontext= mount
. - Przejrzyj każde odrzucenie i utwórz zasady SELinux, aby prawidłowo je obsługiwać. Zobacz przykłady w sekcji Dostosowywanie.
Zacznij od zasad w AOSP, a następnie rozwijaj je, aby wprowadzić własne dostosowania. Więcej informacji o strategii dotyczącej zasad i szczegółowe omówienie niektórych z tych kroków znajdziesz w artykule na temat pisania zasad SELinux.
Przypadki użycia
Oto konkretne przykłady luk w zabezpieczeniach, które warto wziąć pod uwagę podczas tworzenia własnego oprogramowania i powiązanych z nim zasad SELinux:
Symlinki: ponieważ symlinki są widoczne jako pliki, często są odczytywane jako pliki, co może prowadzić do wykorzystania luk w zabezpieczeniach. Na przykład niektóre komponenty uprzywilejowane, takie jak init
, zmieniają uprawnienia do niektórych plików, czasami na zbyt otwarte.
Atakujący mogą następnie zastąpić te pliki dowiązaniami symbolicznymi do kodu, który kontrolują, co pozwala im nadpisywać dowolne pliki. Jeśli jednak wiesz, że Twoja aplikacja nigdy nie korzysta z linków symbolicznych, możesz jej to uniemożliwić za pomocą SELinux.
Pliki systemowe: rozważ, które pliki systemowe powinny być modyfikowane tylko przez serwer systemowy. Jednak ponieważ procesy netd
, init
i vold
działają jako root, mają dostęp do tych plików systemowych. Jeśli netd
zostanie naruszony, może to spowodować naruszenie tych plików, a nawet samego serwera systemowego.
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 przejęty, nie będzie mógł przełączyć domen na domenę serwera systemowego i uzyskać dostępu do tych plików systemowych, mimo że działa jako root.
Dane aplikacji: kolejnym przykładem jest klasa funkcji, które muszą być uruchamiane jako root, ale nie powinny mieć dostępu do danych aplikacji. Jest to niezwykle przydatne, ponieważ można tworzyć szeroki zakres asercji, np. zabraniać dostępu do internetu określonym domenom niezwiązanym z danymi aplikacji.
setattr: w przypadku poleceń takich jak chmod
i chown
możesz określić zestaw plików, w których powiązana domena może przeprowadzać setattr
. Wszystko, co wykracza poza ten zakres, może być zabronione, nawet w przypadku dostępu do roota. Aplikacja może więc uruchamiać testy chmod
i chown
w przypadku użytkowników oznaczonych etykietą app_data_files
, ale nie w przypadku użytkowników oznaczonych etykietami shell_data_files
ani system_data_files
.