Wdrażanie SELinux

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ć nowe file_contexts, ponownie skompiluj obraz systemu plików lub uruchom restorecon w pliku, który ma zostać ponownie oznaczony. Podczas uaktualniania zmiany w file_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łania restorecon_recursive do pliku initboard.rc po zamontowaniu partycji w trybie odczytu i zapisu.
  • genfs_contexts przypisuje etykiety do systemów plików, takich jak proc lub vfat, 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ą opcji context=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 proces init 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 proces servicemanager podczas uruchamiania.
  • seapp_contexts przypisuje etykiety do procesów aplikacji i /data/data katalogów. Ta konfiguracja jest odczytywana przez proces zygote przy każdym uruchomieniu aplikacji i przez installd podczas uruchamiania.
  • mac_permissions.xml przypisuje do aplikacji tag seinfo na podstawie ich podpisu i opcjonalnie nazwy pakietu. Tag seinfo może być używany jako klucz w pliku seapp_contexts do przypisywania określonej etykiety do wszystkich aplikacji z tym tagiem seinfo. Ta konfiguracja jest odczytywana przez system_server podczas uruchamiania.
  • keystore2_key_contexts przypisuje etykiety do przestrzeni nazw Keystore 2. Te przestrzenie nazw są wymuszane przez demona keystore2. 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:

  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
    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.
  3. Uruchom system w trybie zezwalającym i sprawdź, jakie odmowy wystąpią podczas uruchamiania:
    W Ubuntu 14.04 lub nowszym:
    adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/BOARD/root/sepolicy
    
    Ubuntu 12.04:
    adb pull /sys/fs/selinux/policy
    adb logcat -b all | audit2allow -p policy
    
  4. 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.
  5. identyfikować urządzenia i inne nowe pliki, które wymagają etykietowania;
  6. Używaj istniejących lub nowych etykiet obiektów. Sprawdź *_contextspliki, 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.
  7. 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: '
    
  8. 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ł do init lub w inny sposób mylenia dostępu do init z dostępem do własnych zasad.
  9. Skonfiguruj BOARD_CONFIG.mk, aby używać zmiennych BOARD_SEPOLICY_*. Szczegółowe informacje o konfigurowaniu tej funkcji znajdziesz w pliku READMEsystem/sepolicy.
  10. 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.
  11. 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, initvold 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 chmodchown 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 chmodchown 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.