Pisanie polityki SELinux

Projekt Android Open Source Project (AOSP) zapewnia solidne zasady podstawowe dla aplikacji i usług, które są wspólne dla wszystkich urządzeń z systemem Android. Współtwórcy AOSP regularnie udoskonalają tę politykę. Oczekuje się, że zasada podstawowa będzie stanowić około 90–95% ostatecznych zasad dotyczących urządzeń, a pozostałe 5–10% stanowią dostosowania specyficzne dla urządzenia. Ten artykuł koncentruje się na tych dostosowaniach specyficznych dla urządzenia, sposobach pisania zasad specyficznych dla urządzenia i niektórych pułapkach, których należy unikać po drodze.

Przywołanie urządzenia

Podczas pisania zasad dotyczących konkretnych urządzeń wykonaj następujące kroki.

Uruchom w trybie permisywnym

Gdy urządzenie jest w trybie zezwalającym , odmowy są rejestrowane, ale nie są wymuszane. Tryb permisywny jest ważny z dwóch powodów:

  • Tryb zezwalający zapewnia, że ​​wywoływanie zasad nie opóźnia innych zadań wczesnego wywoływania urządzeń.
  • Wymuszona odmowa może maskować inne odmowy. Na przykład dostęp do pliku zazwyczaj pociąga za sobą przeszukanie katalogu, otwarcie pliku, a następnie odczyt pliku. W trybie wymuszania wystąpi tylko odmowa przeszukiwania katalogu. Tryb zezwalający zapewnia, że ​​wszystkie odmowy są widoczne.

Najprostszym sposobem przełączenia urządzenia w tryb zezwalający jest użycie wiersza poleceń jądra . Można to dodać do pliku BoardConfig.mk urządzenia: platform/device/<vendor>/<target>/BoardConfig.mk . Po zmodyfikowaniu wiersza poleceń wykonaj make clean , a następnie make bootimage i flashuj nowy obraz rozruchowy.

Następnie potwierdź tryb zezwalający za pomocą:

adb shell getenforce

Dwa tygodnie to rozsądna ilość czasu, aby być w trybie globalnego zezwolenia. Po rozwiązaniu większości odmów wróć do trybu wymuszania i usuwaj pojawiające się błędy. Domeny wciąż generujące odmowy lub usługi, które wciąż są intensywnie rozwijane, można tymczasowo przełączyć w tryb zezwalający, ale jak najszybciej przenieś je z powrotem do trybu wymuszania.

Egzekwuj wcześnie

W trybie wymuszania odmowy są rejestrowane i wymuszane. Najlepszym rozwiązaniem jest jak najszybsze przełączenie urządzenia w tryb wymuszania. Czekanie na utworzenie i wyegzekwowanie zasad dotyczących konkretnych urządzeń często skutkuje wadliwym produktem i złym doświadczeniem użytkownika. Rozpocznij wystarczająco wcześnie, aby wziąć udział w testowaniu i zapewnić pełne pokrycie testowe funkcjonalności w rzeczywistych zastosowaniach. Wczesne rozpoczęcie zapewnia, że ​​kwestie bezpieczeństwa wpływają na decyzje projektowe. I odwrotnie, przyznawanie uprawnień wyłącznie na podstawie zaobserwowanych odmów jest niebezpiecznym podejściem. Wykorzystaj ten czas, aby przeprowadzić audyt bezpieczeństwa urządzenia i zgłosić błędy pod kątem zachowań, które nie powinny być dozwolone.

Usuń lub usuń istniejące zasady

Istnieje wiele dobrych powodów, aby utworzyć od podstaw zasady specyficzne dla urządzenia na nowym urządzeniu, do których należą:

Zaadresuj odmowę świadczenia usług podstawowych

Odmowy generowane przez usługi podstawowe są zazwyczaj rozwiązywane za pomocą etykietowania plików. Na przykład:

avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0”
dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0
tclass=chr_file permissive=1
avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs"
scontext=u:r:mediaserver:s0
tcontext=u:object_r:device:s0 tclass=chr_file permissive=1

jest całkowicie rozwiązany przez prawidłowe oznaczenie /dev/kgsl-3d0 . W tym przykładzie tcontext to device . Reprezentuje to domyślny kontekst, w którym wszystko w /dev otrzymuje etykietę „ urządzenie ”, chyba że przypisana jest bardziej konkretna etykieta. Po prostu zaakceptowanie danych wyjściowych z audit2allow w tym miejscu skutkowałoby niepoprawną i nadmiernie dopuszczalną regułą.

Aby rozwiązać tego rodzaju problem, nadaj plikowi bardziej konkretną etykietę, którą w tym przypadku jest gpu_device . Nie są potrzebne żadne dalsze uprawnienia, ponieważ mediaserver ma już niezbędne uprawnienia w polityce podstawowej, aby uzyskać dostęp do gpu_device.

Inne pliki specyficzne dla urządzenia, które powinny być oznaczone typami predefiniowanymi w zasadach podstawowych:

Ogólnie rzecz biorąc, przyznawanie uprawnień do etykiet domyślnych jest błędne. Wiele z tych uprawnień jest niedozwolonych przez reguły Neverallow , ale nawet jeśli nie są one wyraźnie zabronione, najlepszą praktyką jest zapewnienie określonej etykiety.

Oznacz nowe usługi i odmowy adresów

Usługi uruchomione przez init muszą działać we własnych domenach SELinux. Poniższy przykład umieszcza usługę „foo” we własnej domenie SELinux i nadaje jej uprawnienia.

Usługa jest uruchamiana w init. device .rc plik init. device .rc jako:

service foo /system/bin/foo
    class core
  1. Utwórz nową domenę „foo”

    Utwórz plik device/ manufacturer / device-name /sepolicy/foo.te z następującą zawartością:

    # foo service
    type foo, domain;
    type foo_exec, exec_type, file_type;
    
    init_daemon_domain(foo)
    

    Jest to początkowy szablon dla domeny foo SELinux, do której możesz dodać reguły oparte na konkretnych operacjach wykonywanych przez ten plik wykonywalny.

  2. Etykieta /system/bin/foo

    Dodaj następujące informacje do device/ manufacturer / device-name /sepolicy/file_contexts :

    /system/bin/foo   u:object_r:foo_exec:s0
    

    Daje to pewność, że plik wykonywalny jest odpowiednio oznakowany, aby SELinux uruchomił usługę w odpowiedniej domenie.

  3. Zbuduj i sflashuj obrazy rozruchowe i systemowe.
  4. Doprecyzuj reguły SELinux dla domeny.

    Użyj odmów, aby określić wymagane uprawnienia. Narzędzie audit2allow zapewnia dobre wytyczne, ale używaj go tylko do informowania o tworzeniu polityki. Nie tylko kopiuj dane wyjściowe.

Przełącz z powrotem do trybu wymuszania

W porządku jest rozwiązywanie problemów w trybie permisywnym, ale jak najszybciej przełącz się z powrotem do trybu wymuszania i staraj się tam pozostać.

Częste błędy

Oto kilka rozwiązań typowych błędów, które zdarzają się podczas pisania zasad dotyczących konkretnych urządzeń.

Nadużywanie negacji

Poniższa przykładowa reguła przypomina zamykanie drzwi wejściowych, ale pozostawianie otwartych okien:

allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms

Intencja jest jasna: wszyscy oprócz aplikacji innych firm mogą mieć dostęp do urządzenia do debugowania.

Zasada jest błędna na kilka sposobów. Wykluczenie untrusted_app jest proste do obejścia, ponieważ wszystkie aplikacje mogą opcjonalnie uruchamiać usługi w domenie isolated_app . Podobnie, jeśli do AOSP zostaną dodane nowe domeny dla aplikacji innych firm, będą one również miały dostęp do scary_debug_device . Zasada jest zbyt liberalna. Większość domen nie skorzysta z dostępu do tego narzędzia do debugowania. Reguła powinna zostać napisana, aby zezwalać tylko na domeny, które wymagają dostępu.

Funkcje debugowania w produkcji

Funkcje debugowania nie powinny być obecne w kompilacjach produkcyjnych ani ich zasad.

Najprostszą alternatywą jest zezwolenie na debugowanie tylko wtedy, gdy SELinux jest wyłączony w kompilacjach eng/userdebug, takich jak adb root i adb shell setenforce 0 .

Inną bezpieczną alternatywą jest uwzględnienie uprawnień debugowania w instrukcji userdebug_or_eng .

Eksplozja wielkości polityki

Charakterystyka SEAndroid Policies in the Wild opisuje niepokojący trend wzrostu dostosowywania zasad dotyczących urządzeń. Zasady specyficzne dla urządzenia powinny stanowić 5–10% ogólnych zasad działających na urządzeniu. Dostosowania w zakresie 20%+ prawie na pewno zawierają ponad uprzywilejowane domeny i martwą politykę.

Niepotrzebnie duża polisa:

  • Podwójnie uderza w pamięć, ponieważ polityka znajduje się w ramdysku i jest również ładowana do pamięci jądra.
  • Marnuje miejsce na dysku, wymagając większego obrazu rozruchowego.
  • Wpływa na czasy wyszukiwania zasad środowiska wykonawczego.

Poniższy przykład przedstawia dwa urządzenia, na których zasady producenta stanowiły 50% i 40% zasad dotyczących urządzenia. Przepisanie zasad przyniosło znaczne ulepszenia bezpieczeństwa bez utraty funkcjonalności, jak pokazano poniżej. (Urządzenia AOSP Shamu i Flounder są dołączone do porównania.)

Rysunek 1: Porównanie rozmiaru polityki dla konkretnego urządzenia po audycie bezpieczeństwa.

Rysunek 1 . Porównanie rozmiaru polityki dla konkretnego urządzenia po audycie bezpieczeństwa.

W obu przypadkach polityka została radykalnie zmniejszona, zarówno pod względem rozmiaru, jak i liczby uprawnień. Zmniejszenie rozmiaru polityki jest prawie całkowicie spowodowane usunięciem niepotrzebnych uprawnień, z których wiele prawdopodobnie było regułami wygenerowanymi przez audit2allow , które zostały bezkrytycznie dodane do polityki. Martwe domeny były również problemem dla obu urządzeń.

Przyznawanie możliwości dac_override

dac_override oznacza, że ​​naruszający prawo proces próbuje uzyskać dostęp do pliku z niepoprawnymi uprawnieniami użytkownika/grupy/świata unixowego. Właściwym rozwiązaniem jest prawie nigdy nie udzielanie uprawnień dac_override . Zamiast tego zmień uprawnienia uniksowe do pliku lub procesu . Kilka domen, takich jak init , vold i installd , naprawdę potrzebuje możliwości nadpisania uprawnień do plików uniksowych, aby uzyskać dostęp do plików innych procesów. Zobacz blog Dana Walsha, aby uzyskać bardziej szczegółowe wyjaśnienie.