Wdrażanie SELinux

SELinux jest domyślnie skonfigurowany tak, aby odmawiać dostępu. Oznacza to, że każdy dostęp, do którego ma on zaczep w jądrze, musi być wyraźnie dozwolony przez zasady. Plik zasad zawiera więc dużą ilość informacji o regułach, typach, klasach, uprawnieniach i innych elementach. Szczegółowe omówienie SELinux wykracza poza zakres tego dokumentu, ale zrozumienie, jak pisać reguły zasad, jest teraz niezbędne podczas konfigurowania nowych urządzeń z Androidem. Dostępnych jest już wiele informacji o SELinux. Sugerowane materiały znajdziesz w Supporting documentation dokumentacji pomocniczej.

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 pliki te tworzą zasady bezpieczeństwa jądra SELinux i obejmują system operacyjny Android.

Zasadniczo nie należy bezpośrednio modyfikować plików system/sepolicy. Zamiast tego dodaj lub edytuj własne pliki zasad specyficzne dla urządzenia w /device/manufacturer/device-name/sepolicy katalogu. W Androidzie 8.0 i nowszych wersjach zmiany wprowadzane w tych plikach powinny wpływać tylko na zasady w katalogu dostawcy. Więcej informacji o rozdzieleniu publicznych zasad SELinux w Androidzie 8.0 i nowszych wersjach znajdziesz w artykule Dostosowywanie zasad SELinux w Androidzie 8.0 i nowszych wersjach. 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 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 aktualizować istniejące pliki.

Pliki kontekstu

W plikach kontekstu 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 aktualizacji zmiany w file_contexts są automatycznie stosowane do partycji systemowej i partycji danych użytkownika w ramach aktualizacji. Zmiany można też automatycznie zastosować podczas aktualizacji do innych partycji, dodając restorecon_recursive wywołania do pliku init.board.rc po zamontowaniu partycji w trybie odczytu i zapisu.
  • genfs_contexts przypisuje etykiety do systemów plików, takich jak proc czy vfat, które nie obsługują rozszerzonych atrybutów. Ta konfiguracja jest wczytywana jako część zasad jądra, ale zmiany mogą nie zostać zastosowane do inode w jądrze, co wymaga ponownego uruchomienia lub odmontowania i ponownego zamontowania systemu plików. Określone etykiety można też przypisać do określonych punktów montowania, 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 init proces podczas uruchamiania.
  • service_contexts przypisuje etykiety do usług Android Binder, aby kontrolować, które procesy mogą dodawać (rejestrować) i znajdować (wyszukiwać) odniesienie do usługi. Ta konfiguracja jest odczytywana przez servicemanager proces 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 oraz przez installd podczas uruchamiania.
  • mac_permissions.xml przypisuje tag seinfo do aplikacji na podstawie ich podpisu i opcjonalnie nazwy pakietu. Tag seinfo można następnie użyć jako klucza w pliku seapp_contexts, aby przypisać określoną etykietę 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 UID/AID. Keystore 2 dodatkowo wymusza przestrzenie nazw zdefiniowane przez zasady SELinux. Szczegółowy opis formatu i konwencji tego pliku znajdziesz tutaj.

Plik makefile BoardConfig.mk

Po edytowaniu lub dodaniu plików zasad i kontekstu zaktualizuj swój /device/manufacturer/device-name/BoardConfig.mk plik 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 ponownym skompilowaniu na urządzeniu jest 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 sprawdzić istniejącą konfigurację zgodnie z opisem w sekcji Weryfikacja.

Gdy nowe pliki zasad i aktualizacje BoardConfig.mk są na miejscu, nowe ustawienia zasad są automatycznie wbudowywane w końcowy plik zasad jądra. Więcej informacji o tym, jak tworzone są zasady SELinux na urządzeniu, znajdziesz w artykule Tworzenie zasad SELinux.

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
    Jest to potrzebne tylko do wstępnego opracowania zasad dla urządzenia. Gdy masz już wstępne zasady bootstrap, usuń ten parametr, aby urządzenie wymuszało zasady lub nie przeszło testów 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 danych wyjściowych nie ma ostrzeżeń podobnych do init: Warning! Service name needs a SELinux domain defined; please fix!. Instrukcje i narzędzia znajdziesz w sekcji Weryfikacja.
  5. Określ urządzenia i inne nowe pliki, które wymagają etykietowania.
  6. Użyj istniejących lub nowych etykiet dla swoich obiektów. Sprawdź pliki *_contexts aby zobaczyć, jak wcześniej oznaczano obiekty i użyj wiedzy 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 kontekstu.
  7. Określ domeny i procesy, które powinny mieć własne domeny bezpieczeństwa. Prawdopodobnie musisz napisać zupełnie nowe zasady dla każdej z nich. Na przykład wszystkie usługi uruchamiane przez init, powinny mieć własne zasady. Te polecenia pomagają wykryć te, 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 innego mylenia dostępu init z dostępem, który jest objęty własnymi zasadami.
  9. Skonfiguruj BOARD_CONFIG.mk, aby używać BOARD_SEPOLICY_* zmiennych. Szczegółowe informacje o konfiguracji znajdziesz w pliku README w system/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. Sprawdź każdą odmowę i utwórz zasady SELinux, aby prawidłowo ją obsługiwać. Przykłady znajdziesz w sekcji Dostosowywanie.

Zacznij od zasad w AOSP, a następnie rozbuduj je o własne dostosowania. Więcej informacji o strategii zasad i a szczegółowe omówienie niektórych z tych kroków znajdziesz w artykule Pisanie zasad SELinux.

Przypadki użycia

Oto konkretne przykłady luk w zabezpieczeniach, które należy 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 z uprawnieniami, takie jak init, zmieniają uprawnienia do niektórych plików, czasami na zbyt otwarte.

Hakerzy mogą następnie zastąpić te pliki symlinkami do kodu, który kontrolują, co pozwala im nadpisywać dowolne pliki. Jeśli jednak wiesz, że Twoja aplikacja nigdy nie przechodzi przez symlink, możesz zabronić jej tego za pomocą SELinux.

Pliki systemowe: rozważ klasę plików systemowych, które powinny być modyfikowane tylko przez serwer systemowy. Jednak ponieważ netd, init i vold działają jako root, mogą uzyskiwać dostęp do tych plików systemowych. Jeśli więc netd zostanie naruszony, może naruszyć te pliki i potencjalnie sam serwer systemowy.

Za pomocą 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 mógł przełączyć się na domenę serwera systemowego i uzyskać dostępu do tych plików systemowych, mimo że działa jako root.

Dane aplikacji: innym 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ć szeroko zakrojone asercje, np. zabronić niektórym domenom niezwiązanym z danymi aplikacji dostępu do internetu.

setattr: w przypadku poleceń takich jak chmod i chown możesz określić zestaw plików, w których powiązana domena może wykonywać setattr. Wszystko poza tym może być zabronione, nawet przez roota. Aplikacja może więc uruchamiać chmod i chown w przypadku plików oznaczonych jako app_data_files, ale nie shell_data_files ani system_data_files.