Wdrażanie SELinux

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ć nowe file_contexts, ponownie utwórz obraz systemu plików lub uruchom polecenie restorecon w pliku, którego etykiety chcesz zmienić. Podczas przekształcania zmiany w file_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łania restorecon_recursive po zamontowaniu partycji do odczytu i zapisu.
  • genfs_contexts przypisuje etykiety do systemów plików, takich jak proc lub vfat, 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 jak vfat, za pomocą opcji context=mount.
  • property_contexts przypisuje etykiety właściwościom systemu Android, aby kontrolować, które procesy mogą je ustawiać. Ta konfiguracja jest odczytywana przez proces init 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 proces servicemanager podczas uruchamiania.
  • seapp_contexts przypisuje etykiety do procesów aplikacji i katalogów /data/data. Ta konfiguracja jest odczytywana przez proces zygote przy każdym uruchomieniu aplikacji oraz przez installd podczas uruchamiania.
  • mac_permissions.xml przypisuje tag seinfo do aplikacji na podstawie ich sygnatury i opcjonalnie nazwy pakietu. Tagseinfo można następnie wykorzystać jako klucz w pliku seapp_contexts, aby przypisać określoną etykietę do wszystkich aplikacji z tym tagiem seinfo. 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:

  1. Włącz SELinux w jądrze:CONFIG_SECURITY_SELINUX=y
  2. Zmień parametr kernel_cmdline lub bootconfig tak, aby:
    BOARD_KERNEL_CMDLINE := androidboot.selinux=permissive
    lub
    BOARD_BOOTCONFIG := 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.
  3. Uruchom system w trybie zezwalającym i sprawdź, jakie odmowy występują podczas uruchamiania:
    W Ubuntu 14.04 lub nowszym:
    adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/BOARD/root/sepolicy
    
    W Ubuntu 12.04:
    adb pull /sys/fs/selinux/policy
    adb logcat -b all | audit2allow -p policy
    
  4. 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.
  5. Określanie urządzeń i innych nowych plików, które wymagają oznaczenia.
  6. 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.
  7. 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: '
    
  8. 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ł do init lub mylenia dostępów init z dostępami w ich własnych zasadach.
  9. Aby używać zmiennych BOARD_SEPOLICY_*, skonfiguruj BOARD_CONFIG.mk. Szczegółowe informacje na temat konfigurowania tej funkcji znajdziesz w pliku README w system/sepolicy.
  10. 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.
  11. 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, initvold 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ł chmodchown, ale nie shell_data_files ani system_data_files.app_data_files