Zgodność z zasadami

Z tego artykułu dowiesz się, jak Android obsługuje problemy ze zgodnością zasad w przypadku aktualizacji OTA platformy, w których nowe ustawienia SELinux platformy mogą się różnić od starych ustawień SELinux dostawcy.

Projektowanie zasad SELinux na podstawie Treble uwzględnia binarne rozróżnienie między zasadami platformydostawcy. Schemat staje się bardziej skomplikowany, jeśli partycje dostawcy generują zależności, takie jak platform < vendor < oem.

W Androidzie 8.0 i nowszych polityka globalna SELinux jest podzielona na komponenty prywatne i publiczne. Komponenty publiczne to zasady i powiązana z nimi infrastruktura, które są dostępne w przypadku danej wersji platformy. Ta zasada będzie dostępna dla autorów zasad dostawców, aby umożliwić im tworzenie pliku zasad dostawcy, który w połączeniu z zasadami udostępnionymi przez platformę zapewni pełną funkcjonalność zasad na urządzeniu.

  • W przypadku wersji wyeksportowane zasady publiczne platformy zostaną zapisane jako atrybuty.
  • Aby ułatwić tworzenie zasad, w ramach procesu tworzenia zasad typy eksportowane zostaną przekształcone w atrybuty z wersją. Publiczne typy mogą być też używane bezpośrednio w decyzjach dotyczących etykietowania w plikach kontekstów dostawcy.

Android utrzymuje mapowanie między eksportowanymi typami konkretnych danych w zasadach dotyczących platformy a odpowiednimi atrybutami z wersją dla każdej wersji platformy. Dzięki temu, gdy obiekty są oznaczone typem, nie naruszają one zasad obowiązujących w danej platformie w poprzedniej wersji. Mapowanie jest aktualizowane przez utrzymywanie aktualnego pliku mapowania dla każdej wersji platformy, który zawiera informacje o przynależności atrybutu do każdego typu wyeksportowanego w zasadach publicznych.

Własność obiektu i oznaczanie

Podczas dostosowywania zasad w Androidzie w wersji 8.0 lub nowszej należy wyraźnie określić własność każdego obiektu, aby oddzielić zasady platformy od zasad dostawcy. Jeśli na przykład dostawca oznaczy element jako /dev/foo, a platforma oznaczy go jako /dev/foo w kolejnych aktualizacjach OTA, zachowanie będzie nieokreślone. W przypadku SELinux powoduje to kolizję etykiet. Węzeł urządzenia może mieć tylko jedną etykietę, która jest rozwiązywana do ostatniej zastosowanej etykiety. W rezultacie:

  • Procesy, które potrzebują dostępu do etykiety zastosowanej bez powodzenia, stracą dostęp do zasobu.
  • Procesy, które uzyskają dostęp do pliku, mogą się nie uruchomić, ponieważ utworzono niewłaściwy węzeł urządzenia.

Właściwości systemowe mogą też powodować kolizje nazw, które mogą skutkować nieokreślonym działaniem systemu (a także etykietowaniem SELinux). Kolizje między etykietami platformy i usługodawcy mogą wystąpić w przypadku dowolnego obiektu z etykietą SELinux, w tym usług, procesów, plików i gniazd. Aby uniknąć tych problemów, jasno określ własność tych obiektów.

Oprócz kolizji etykiet mogą też występować kolizje nazw typów/atrybutów SELinux. Kolizja nazw typu lub atrybutu zawsze powoduje błąd kompilatora zasad.

Nazewnictwo typów i atrybutów

SELinux nie zezwala na wielokrotne deklaracje tego samego typu/atrybutu. Kompilacja zasad z powtarzającymi się deklaracjami zakończy się niepowodzeniem. Aby uniknąć kolizji nazw typów i atrybutów, wszystkie deklaracje dostawców powinny być umieszczane w przestrzeni nazw zaczynającej się od vendor_.

type foo, domain;  type vendor_foo, domain;

Własność etykietowania właściwości systemowych i procesów

Aby uniknąć kolizji etykiet, najlepiej użyć przestrzeni nazw właściwości. Aby łatwo identyfikować właściwości platformy i unikać konfliktów nazw podczas ich zmiany lub dodawania na platformach wyeksportowanych, upewnij się, że wszystkie właściwości dostawcy mają własne prefiksy:

Typ obiektu Dopuszczalne prefiksy
właściwości kontrolne ctl.vendor.
ctl.start$vendor.
ctl.stop$vendor.
init.svc.vendor.
odczyt i zapis vendor.
tylko do odczytu ro.vendor.
ro.boot.
ro.hardware.
trwałe persist.vendor.

Dostawcy mogą nadal używać ro.boot.* (który pochodzi z jądra cmdline) i ro.hardware.* (czyli właściwości związanej z sprzętem).

Wszystkie usługi dostawcy w plikach init rc powinny mieć vendor. w przypadku usług w plikach init rc w partycjach niesystemowych. Podobne reguły są stosowane do etykiet SELinux w usługach dostawców (vendor_).

Własność pliku

Zapobieganie kolizjom plików jest trudne, ponieważ zarówno platformy, jak i dostawcy często udostępniają etykiety dla wszystkich systemów plików. W przeciwieństwie do nazewnictwa typów stosowanie nazw przestrzeni nazw plików nie jest praktyczne, ponieważ wiele z nich jest tworzonych przez jądro. Aby uniknąć takich kolizji, postępuj zgodnie ze wskazówkami dotyczącymi nazewnictwa systemów plików podanymi w tej sekcji. W przypadku Androida 8.0 są to zalecenia bez technicznego egzekwowania. W przyszłości te rekomendacje będą egzekwowane przez pakiet testów dostawcy (VTS).

System (/system)

Etykiety dla komponentów /system do file_contexts, service_contexts itd. musi zawierać tylko obraz systemu. Jeśli etykiety dla komponentów /system zostaną dodane w zasadach /vendor, aktualizacja OTA tylko dla frameworku może okazać się niemożliwa.

Dostawca (/vendor)

Zasady SELinux w AOSP już oznaczają części partycji vendor, z którymi platforma wchodzi w interakcje. Umożliwia to tworzenie reguł SELinux dla procesów platformy, aby mogły one komunikować się z częściami partycji vendor lub uzyskiwać do nich dostęp. Przykłady:

Ścieżka elementu „/vendor Etykieta udostępniona przez platformę Procesy platformy w zależności od etykiety
/vendor(/.*)? vendor_file Wszyscy klienci HAL w ramach, ueventd itd.
/vendor/framework(/.*)? vendor_framework_file dex2oat, appdomain itp.
/vendor/app(/.*)? vendor_app_file dex2oat, installd, idmap itp.
/vendor/overlay(/.*) vendor_overlay_file system_server, zygote, idmap itp.

W związku z tym podczas etykietowania dodatkowych plików w partycji vendor należy przestrzegać określonych reguł (przestrzeganych za pomocą neverallows):

  • vendor_file musi być domyślną etykietą wszystkich plików na partycji vendor. Zasady platformy wymagają tego, aby uzyskać dostęp do implementacji przepustki HAL.
  • Wszystkie nowe exec_types dodane w partycji vendor za pomocą SEPolicy dostawcy muszą mieć atrybut vendor_file_type. Ta zasada jest egzekwowana za pomocą reguły neverallows.
  • Aby uniknąć konfliktów z przyszłymi aktualizacjami platformy lub platformy, nie etykietuj plików innych niż exec_types w partycji vendor.
  • Wszystkie zależności bibliotek dla identyfikowanych przez AOSP interfejsów HAL dla tego samego procesu muszą być oznaczone jako same_process_hal_file.

procfs (/proc)

Pliki w /proc mogą być oznaczane tylko etykietą genfscon. W Androidzie 7.0 zarówno platforma, jak i dostawca używają zasad genfscon do oznaczania plików w procfs.

Zalecenie: tylko etykiety zasad platformy /proc. Jeśli procesy vendor wymagają dostępu do plików w /proc, które są obecnie oznaczone etykietą domyślną (proc), polityka dostawcy nie powinna ich wyraźnie oznaczać. Zamiast tego należy użyć ogólnego typu proc, aby dodać reguły dla domen dostawcy. Dzięki temu aktualizacje platformy mogą uwzględniać przyszłe interfejsy jądra udostępniane przez procfs i w razie potrzeby wyraźnie je oznaczać.

Debugfs (/sys/kernel/debug)

Debugfs może być oznaczony w przypadku zarówno file_contexts, jak i genfscon. W Androidzie 7.0–10 obie etykiety: platformy i producentadebugfs.

W Androidzie 11 nie można uzyskać dostępu do debugfs ani zamontować go na urządzeniach produkcyjnych. Producenci urządzeń powinni usunąć debugfs.

Tracefs (/sys/kernel/debug/tracing)

Tracefs może być oznaczony w przypadku zarówno file_contexts, jak i genfscon. W Androidzie 7.0 tylko etykiety platformy.tracefs

Rekomendacja: tylko platforma może oznaczać tracefs.

Sysfs (/sys)

Pliki w /sys mogą być oznaczone etykietami file_contexts i genfscon. W Androidzie 7.0 zarówno platforma, jak i producent używają etykiety genfscon do oznaczania plików w folderze sysfs.

Rekomendacja: platforma może oznaczać etykietą sysfs węzły, które nie są powiązane z konkretnym urządzeniem. W przeciwnym razie tylko dostawca może etykietować pliki.

tmpfs (/dev)

Pliki w folderze /dev mogą mieć etykiety w folderze file_contexts. W Androidzie 7.0 pliki etykiet platformy i usługodawcy.

Zalecenie: dostawca może oznaczać etykietami tylko pliki w /dev/vendor (np. /dev/vendor/foo, /dev/vendor/socket/bar).

rootfs (/)

Pliki w folderze / mogą mieć etykiety w folderze file_contexts. W Androidzie 7.0 pliki etykiet platformy i dostawcy.

Zalecenie: tylko system może oznaczać pliki w /.

Data (/data)

Dane są oznaczane za pomocą kombinacji atrybutów file_contexts i seapp_contexts.

Rekomendacja: nie zezwalaj na etykietowanie przez dostawcę poza /data/vendor. Tylko platforma może oznaczać inne części /data.

Wersja etykiet Genfs

Od poziomu interfejsu API dostawcy 202504 nowsze etykiety SELinux przypisane za pomocą genfsconsystem/sepolicy/compat/plat_sepolicy_genfs_{ver}.cil są opcjonalne w przypadku starszych partycji dostawcy. Umożliwia to starszym partycjom dostawcy zachowanie dotychczasowej implementacji SEPolicy. Jest ona kontrolowana przez zmienną Makefile BOARD_GENFS_LABELS_VERSION, która jest przechowywana w pliku /vendor/etc/selinux/genfs_labels_version.txt.

Przykład:

  • Na poziomie interfejsu API dostawcy 202404 węzeł /sys/class/udc jest domyślnie oznaczony jako sysfs.
  • Od poziomu interfejsu API dostawcy 202504 /sys/class/udc ma etykietę sysfs_udc.

Jednak /sys/class/udc może być używane przez partycje dostawcy korzystające z poziomu interfejsu API 202404, z domyślną etykietą sysfs lub etykietą specyficzną dla dostawcy. Bezwarunkowe oznaczenie /sys/class/udc jako sysfs_udc może spowodować utratę zgodności z tymi partycjami dostawcy. Jeśli zaznaczysz BOARD_GENFS_LABELS_VERSION, platforma będzie nadal używać poprzednich etykiet i uprawnień w przypadku starszych partycji dostawcy.

Wartość BOARD_GENFS_LABELS_VERSION może być równa lub większa niż poziom interfejsu API dostawcy. Na przykład partycje dostawcy korzystające z poziomu interfejsu API 202404 mogą ustawić wartość BOARD_GENFS_LABELS_VERSION na 202504, aby zastosować nowe etykiety wprowadzone w wersji 202504. Zobacz listę etykiet genfs dla wersji 202504.

Podczas etykietowania węzłów genfscon platforma musi wziąć pod uwagę starsze partycje dostawcy i w razie potrzeby zastosować mechanizmy zastępcze w celu zapewnienia zgodności. Platforma może używać bibliotek przeznaczonych tylko dla tej platformy do zapytania o wersję etykiet genfs.

Atrybuty zgodności

Zasady SELinux to interakcja między typami źródła i docelownika w przypadku określonych klas obiektów i uprawnień. Każdy obiekt (procesy, pliki itp.), na który mają wpływ zasady SELinux, może mieć tylko jeden typ, ale ten typ może mieć wiele atrybutów.

Zasady są sformułowane głównie w ujęciu istniejących typów:

allow source_type target_type:target_class permission(s);

To działa, ponieważ zasady zostały opracowane z uwzględnieniem wszystkich typów. Jeśli jednak zasady dostawcy i zasady platformy używają określonych typów, a etykieta konkretnego obiektu zmienia się tylko w jednej z tych zasad, druga może zawierać zasady, które uzyskały lub utraciły dostęp, na których wcześniej się opierano. Przykład:

File_contexts:
/sys/A   u:object_r:sysfs:s0
Platform: allow p_domain sysfs:class perm;
Vendor: allow v_domain sysfs:class perm;

Można je zmienić na:

File_contexts:
/sys/A   u:object_r:sysfs_A:s0

Chociaż zasady dostawcy pozostaną takie same, v_domain utraci dostęp z powodu braku zasad dotyczących nowego typu sysfs_A

Definiując zasady w terminach atrybutów, możemy nadać obiektowi bazowemu typ, który ma atrybut odpowiadający zasadom zarówno dla platformy, jak i kodu dostawcy. Można to zrobić w przypadku wszystkich typów, aby skutecznie utworzyć zasady dotyczące atrybutów, w których konkretne typy nigdy nie są używane. W praktyce jest to wymagane tylko w przypadku części zasad, które pokrywają się w przypadku platformy i dostawcy. Są one zdefiniowane i udostępniane jako zasady publiczne platformy, które są tworzone w ramach zasad dostawcy.

Zdefiniowanie publicznych zasad jako atrybutów z wersją spełnia 2 cele dotyczące zgodności z zasadami:

  • Upewnij się, że kod dostawcy nadal działa po aktualizacji platformy. Osiągane przez dodawanie atrybutów do konkretnych typów obiektów odpowiadających tym, na których oparty jest kod dostawcy, z zachowaniem dostępu.
  • Możliwość wycofania zasady. Osiąga się to poprzez wyraźne wyodrębnienie zbiorów zasad w atrybuty, które można usunąć, gdy tylko wersja, do której one pasują, przestanie być obsługiwana. Rozwój może być kontynuowany na platformie, ponieważ wiadomo, że stara zasada jest nadal obecna w zasadach dostawcy i zostanie automatycznie usunięta, gdy nastąpi uaktualnienie.

Możliwość zapisu zasad

Aby spełnić cel polegający na tym, że tworzenie zasad nie wymaga znajomości zmian w konkretnej wersji, Android 8.0 zawiera mapowanie typów zasad publicznych na platformie i ich atrybutów. Typ foo jest mapowany na atrybut foo_vN, gdzie N to wersja docelowa. vN odpowiada zmiennej kompilacji PLATFORM_SEPOLICY_VERSION i ma postać MM.NN, gdzie MM odpowiada numerowi pakietu SDK platformy, a NN to wersja platformy do konkretnej polityki bezpieczeństwa.

Atrybuty w publicznych zasadach nie są powiązane z wersją, ale występują jako interfejs API, na którym można budować zasady platformy i usługodawcy, aby utrzymać stabilność interfejsu między tymi dwoma obszarami. Zarówno platformy, jak i dostawcy mogą nadal pisać zasady w taki sposób, w jaki są one obecnie sformułowane.

Zasady publiczne platformy wyeksportowane jako allow source_foo target_bar:class perm; są uwzględnione w zasadach dostawcy. Podczas kompilacji (która obejmuje odpowiednią wersję) jest przekształcana w zasady, które zostaną przekazane do części dostawcy urządzenia (wyświetlane w przekształconym wspólnym języku pośrednim):

 (allow source_foo_vN target_bar_vN (class (perm)))

Zasady dostawcy nigdy nie wyprzedzają platformy, więc nie powinny dotyczyć wcześniejszych wersji. Jednak zasady platformy muszą uwzględniać, jak daleko wstecz sięga polityka dostawcy, jakie atrybuty i typy atrybutów są uwzględnione oraz jakie zasady odpowiadają atrybutom z wersją.

Różnice w zasadach

Automatyczne tworzenie atrybutów przez dodanie _vN na końcu każdego typu nie ma żadnego znaczenia bez mapowania atrybutów na typy w ramach różnic między wersjami. Android utrzymuje mapowanie wersji atrybutów oraz mapowanie typów na te atrybuty. Jest to realizowane w wymienionych wyżej plikach mapowania za pomocą instrukcji takich jak (CIL):

(typeattributeset foo_vN (foo))

Aktualizacje platformy

W sekcji poniżej znajdziesz szczegółowe informacje o scenariuszach uaktualniania platformy.

Takie same typy

Ten scenariusz występuje, gdy obiekt nie zmienia etykiet w wersjach zasad. Jest to takie samo w przypadku typów źródeł i docelowo. Można to zobaczyć w przypadku /dev/binder, który jest oznaczony jako binder_device we wszystkich wersjach. W przekształconej polityce jest on reprezentowany jako:

binder_device_v1 … binder_device_vN

W przypadku przejścia z poziomu v1 na v2 zasady platformy muszą zawierać:

type binder_device; -> (type binder_device) (in CIL)

W pliku mapowania v1 (CIL):

(typeattributeset binder_device_v1 (binder_device))

W pliku mapowania v2 (CIL):

(typeattributeset binder_device_v2 (binder_device))

W zasadach dostawcy w wersji 1 (CIL):

(typeattribute binder_device_v1)
(allow binder_device_v1 )

W zasadach dostawcy w wersji 2 (CIL):

(typeattribute binder_device_v2)
(allow binder_device_v2 )
Nowe typy

Ten scenariusz występuje, gdy platforma doda nowy typ, co może się zdarzyć podczas dodawania nowych funkcji lub wzmacniania zasad.

  • Nowa funkcja. Jeśli typ oznacza obiekt, który wcześniej nie istniał (np. nowy proces usługi), kod dostawcy nie był wcześniej z nim bezpośrednio powiązany, więc nie ma odpowiednich zasad. Nowy atrybut odpowiadający temu typowi nie ma atrybutu w poprzedniej wersji, więc nie wymaga wpisu w pliku mapowania kierowanym na tę wersję.
  • Wzmacnianie zasad. Gdy typ reprezentuje zaostrzenie zasad, nowy atrybut typu musi wskazywać na łańcuch atrybutów odpowiadających poprzedniemu (podobnie jak w poprzednim przykładzie, w którym wartość /sys/A została zmieniona z sysfs na sysfs_A). Kod dostawcy opiera się na regule umożliwiającej dostęp do atrybutu sysfs i musi zawierać tę regułę jako atrybut nowego typu.

W przypadku przejścia z poziomu v1 na v2 zasady platformy muszą zawierać:

type sysfs_A; -> (type sysfs_A) (in CIL)
type sysfs; (type sysfs) (in CIL)

W pliku mapowania v1 (CIL):

(typeattributeset sysfs_v1 (sysfs sysfs_A))

W pliku mapowania v2 (CIL):

(typeattributeset sysfs_v2 (sysfs))
(typeattributeset sysfs_A_v2 (sysfs_A))

W zasadach dostawcy w wersji 1 (CIL):

(typeattribute sysfs_v1)
(allow  sysfs_v1 )

W zasadach dostawcy w wersji 2 (CIL):

(typeattribute sysfs_A_v2)
(allow  sysfs_A_v2 )
(typeattribute sysfs_v2)
(allow  sysfs_v2 )
Typy usunięte

Ten (rzadki) scenariusz występuje, gdy usuwany jest typ, co może się zdarzyć, gdy obiekt źródłowy:

  • Pozostanie, ale otrzyma inną etykietę.
  • został usunięty przez platformę;

Podczas łagodzenia zasad dany typ jest usuwany, a obiekt oznaczony tym typem otrzymuje inną, już istniejącą etykietę. Jest to przykład scalania mapowań atrybutów: kod dostawcy musi nadal mieć dostęp do obiektu podstawowego za pomocą atrybutu, który był używany wcześniej, ale reszta systemu musi teraz mieć dostęp do obiektu za pomocą nowego atrybutu.

Jeśli atrybut, na który została przełączona etykieta, jest nowy, zmiana etykiety przebiega tak samo jak w przypadku nowego typu, z tym że gdy używana jest istniejąca etykieta, dodanie nowego typu starego atrybutu spowoduje, że inne obiekty z tą etykietą również staną się dostępne. Platforma robi to właśnie w podstawie, co jest akceptowalną kompromisem w celu zachowania zgodności.

(typeattribute sysfs_v1)
(allow  sysfs_v1 )

Przykład wersji 1: upatrywanie typów (usuwanie sysfs_A)

W przypadku przejścia z poziomu v1 na v2 zasady platformy muszą zawierać:

type sysfs; (type sysfs) (in CIL)

W pliku mapowania v1 (CIL):

(typeattributeset sysfs_v1 (sysfs))
(type sysfs_A) # in case vendors used the sysfs_A label on objects
(typeattributeset sysfs_A_v1 (sysfs sysfs_A))

W pliku mapowania v2 (CIL):

(typeattributeset sysfs_v2 (sysfs))

W zasadach dostawcy w wersji 1 (CIL):

(typeattribute sysfs_A_v1)
(allow  sysfs_A_v1 )
(typeattribute sysfs_v1)
(allow  sysfs_v1 )

W zasadach dostawcy w wersji 2 (CIL):

(typeattribute sysfs_v2)
(allow  sysfs_v2 )

Przykład wersji 2: usuwanie całkowicie (typ foo)

W przypadku przejścia z poziomu v1 na v2 zasady platformy muszą zawierać:

# nothing - we got rid of the type

W pliku mapowania v1 (CIL):

(type foo) #needed in case vendors used the foo label on objects
(typeattributeset foo_v1 (foo))

W pliku mapowania v2 (CIL):

# nothing - get rid of it

W zasadach dostawcy w wersji 1 (CIL):

(typeattribute foo_v1)
(allow foo )
(typeattribute sysfs_v1)
(allow sysfs_v1 )

W zasadach dostawcy w wersji 2 (CIL):

(typeattribute sysfs_v2)
(allow sysfs_v2 )
Nowe zajęcia lub uprawnienia

Ten scenariusz ma miejsce, gdy uaktualnienie platformy wprowadza nowe komponenty zasad, które nie występują w poprzednich wersjach. Gdy na przykład Android dodał menedżera obiektów servicemanager, który utworzył uprawnienia do dodawania, wyszukiwania i wyświetlania, demony dostawców, które chcą się zarejestrować w servicemanager, potrzebowały uprawnień, których nie było. W Androidzie 8.0 tylko zasady platformy mogą dodawać nowe klasy i uprawnienia.

Aby umożliwić wszystkim domenom, które mogły zostać utworzone lub rozszerzone przez zasady dostawcy, korzystanie z nowej klasy bez ograniczeń, zasada platformy musi zawierać regułę podobną do tej:

allow {domain -coredomain} *:new_class perm;

Może to wymagać zasady zezwalającej na dostęp dla wszystkich typów interfejsów (publiczna zasada), aby mieć pewność, że obraz dostawcy uzyska dostęp. Jeśli spowoduje to nieakceptowalną politykę zabezpieczeń (jak w przypadku zmian w servicemanager), może być konieczne wymuszenie aktualizacji przez dostawcę.

Usunięcie zajęć lub uprawnień

Ten scenariusz występuje, gdy usuwasz menedżera obiektu (np. menedżera obiektu ZygoteConnection) i nie powinien powodować problemów. Klasa menedżera obiektów i uprawnienia mogą pozostać zdefiniowane w zasadach, dopóki wersja dostawcy nie przestanie ich używać. W tym celu należy dodać definicje do odpowiedniego pliku mapowania.

dostosowywanie przez dostawcę nowych lub zmienionych typów;

Nowe typy dostawców są podstawą tworzenia zasad dotyczących dostawców, ponieważ są potrzebne do opisywania nowych procesów, plików binarnych, urządzeń, podsystemów i przechowywanych danych. Dlatego konieczne jest zezwolenie na tworzenie typów zdefiniowanych przez dostawcę.

Ponieważ zasady dostawcy są zawsze najstarszymi na urządzeniu, nie ma potrzeby automatycznego konwertowania wszystkich typów dostawców na atrybuty w zasadach. Platforma nie korzysta z nic oznaczonego w zasadach dostawcy, ponieważ nie ma o nich żadnej wiedzy. Udostępnia jednak atrybuty i publiczne typy, których używa do interakcji z obiektmi oznaczonymi tymi typami (np. domain, sysfs_type itp.). Aby platforma mogła nadal prawidłowo współpracować z tymi obiektami, atrybuty i typy muszą być odpowiednio stosowane, a w przypadku domen z możliwością dostosowania (takich jak init) może być konieczne dodanie określonych reguł.

Zmiany atrybutów w Androidzie 9

Urządzenia aktualizowane do Androida 9 mogą używać tych atrybutów, ale nie mogą ich używać urządzenia uruchamiane z Androidem 9.

Atrybuty naruszyciela

Android 9 zawiera te atrybuty związane z domeną:

  • data_between_core_and_vendor_violators. Atrybut dla wszystkich domen, które naruszają wymóg nieudostępniania plików przez ścieżkę między vendor i coredomains. Procesy platformy i dostawców nie powinny używać plików na dysku do komunikacji (niestabilny ABI). Rekomendacja:
    • Kod dostawcy powinien zawierać /data/vendor.
    • System nie może używać /data/vendor.
  • system_executes_vendor_violators.Atrybut dla wszystkich domen systemowych (z wyjątkiem initshell domains), które naruszają wymóg nieuruchamiania binarek dostawców. Wykonywanie binarnych plików dostawcy z niestabilnym interfejsem API. Platforma nie powinna bezpośrednio wykonywać plików binarnych dostawcy. Rekomendacja:
    • Takie zależności platformy od plików binarnych dostawcy muszą być zaimplementowane za pomocą interfejsów HIDL HAL.

      LUB

    • coredomains, które wymagają dostępu do plików binarnych dostawcy, powinny zostać przeniesione na partycję dostawcy, przez co przestaną być coredomain.

Niegodne zaufania atrybuty

Niezaufane aplikacje, które zawierają dowolny kod, nie powinny mieć dostępu do usług HwBinder, z wyjątkiem tych, które są uznawane za wystarczająco bezpieczne (patrz niżej „Bezpieczne usługi”). Wynika to z 2 głównych powodów:

  1. Serwery HwBinder nie przeprowadzają uwierzytelniania klienta, ponieważ HIDL obecnie nie udostępnia informacji o UID dzwoniącego. Nawet jeśli HIDL udostępnia takie dane, wiele usług HwBinder działa na poziomie niższym niż aplikacje (np. HAL) lub nie może polegać na tożsamości aplikacji w celu autoryzacji. Dlatego, aby zachować bezpieczeństwo, domyślnie zakładamy, że każda usługa HwBinder traktuje wszystkich swoich klientów jako równych sobie w wykonaniu operacji oferowanych przez usługę.
  2. Serwery HAL (podzbiór usług HwBinder) zawierają kod, który ma większą częstotliwość występowania problemów z bezpieczeństwem niż komponenty system/core. Mają one dostęp do niższych warstw stosu (aż do sprzętu), co zwiększa możliwości obejścia modelu zabezpieczeń Androida.

Bezpieczne usługi

Bezpieczne usługi to m.in.:

  • same_process_hwserviceTe usługi (z definicji) działają w procesie klienta, więc mają ten sam dostęp co domena klienta, w której działa proces.
  • coredomain_hwservice. Te usługi nie stwarzają ryzyka związanego z przyczyną #2.
  • hal_configstore_ISurfaceFlingerConfigs. Ta usługa jest przeznaczona do użytku w dowolnej domenie.
  • hal_graphics_allocator_hwservice. Te operacje są też dostępne w usłudze surfaceflinger Binder, do której aplikacje mogą uzyskać dostęp.
  • hal_omx_hwservice. To wersja usługi Binder mediacodec w ramach interfejsu HwBinder, do której aplikacje mogą uzyskać dostęp.
  • hal_codec2_hwservice. Jest to nowsza wersja programu hal_omx_hwservice.

Atrybuty, które można wykorzystać

Wszystkie hwservices, które nie są uważane za bezpieczne, mają atrybut untrusted_app_visible_hwservice. Odpowiednie serwery HAL mają atrybut untrusted_app_visible_halserver. Urządzenia z Androidem 9 NIE MOGĄ używać atrybutu untrusted.

Rekomendacja:

  • Zamiast tego aplikacje o nieznanej reputacji powinny komunikować się z usługą systemową, która komunikuje się z interfejsem HIDL dostawcy. Aplikacje mogą na przykład komunikować się z binderservicedomain, a następnie z mediaserver (który jest binderservicedomain), a ten z kolei z hal_graphics_allocator.

    LUB

  • Aplikacje, które wymagają bezpośredniego dostępu do vendor HAL, powinny mieć własną domenę sepolicy zdefiniowaną przez dostawcę.

Testy atrybutów pliku

Android 9 zawiera testy w czasie kompilacji, które sprawdzają, czy wszystkie pliki w określonych lokalizacjach mają odpowiednie atrybuty (np. czy wszystkie pliki w sysfs mają wymagany atrybut sysfs_type).

Zasady dotyczące platformy i publiczne

Zasady dotyczące platformy publicznej są podstawą zgodności z modelem architektury Androida 8.0, a nie tylko podtrzymaniem unionu zasad platformy z wersji 1 i 2. Dostawcy mają dostęp do podzbioru zasad platformy, który zawiera przydatne typy i atrybuty oraz reguły dotyczące tych typów i atrybutów. Zasady te stają się częścią zasad dostawcy (czyli vendor_sepolicy.cil).

Typy i zasady są automatycznie tłumaczone w zasadach generowanych przez dostawcę na attribute_vN, dzięki czemu wszystkie typy udostępniane przez platformę są atrybutami z wersją (chociaż atrybuty nie mają wersji). Platforma jest odpowiedzialna za mapowanie konkretnych typów na odpowiednie atrybuty, aby zapewnić, że zasady dostawcy będą nadal działać i że uwzględnione zostaną reguły określone dla danej wersji. Połączenie zasad dotyczących platformy i publicznych zasad dostawcy spełnia cel modelu architektury Androida 8.0, który umożliwia niezależne kompilacje platform i dostawców.

Mapowanie na łańcuchy atrybutów

Gdy używasz atrybutów do mapowania wersji zasad, typ jest mapowany na atrybut lub wiele atrybutów, co zapewnia, że obiekty opisane tym typem są dostępne za pomocą atrybutów odpowiadających ich poprzednim typom.

Utrzymywanie celu polegającego na ukrywaniu informacji o wersji przed autorem zasad oznacza automatyczne generowanie atrybutów z wersją i przypisywanie ich do odpowiednich typów. W przypadku typów statycznych jest to proste:type_foo odpowiada type_foo_v1.

W przypadku zmiany etykiety obiektu, np. sysfs → sysfs_A lub mediaserver → audioserver, utworzenie tego mapowania nie jest trywialne (i jest opisane w powyższych przykładach). Administratorzy zasad platformy muszą określić, jak tworzyć mapowanie w punktach przejścia dla obiektów. Wymaga to zrozumienia relacji między obiektami a przypisanymi do nich etykietami oraz określenia, kiedy to ma miejsce. Ze względu na zgodność z wcześniejszymi wersjami należy zarządzać tą złożonością po stronie platformy, która jest jedyną partycją, która może być aktualizowana.

Wersje wstecz

Dla ułatwienia platforma Android udostępnia wersję sepolicy, gdy tworzona jest nowa gałąź wersji. Jak opisano powyżej, numer wersji znajduje się w PLATFORM_SEPOLICY_VERSION i ma postać MM.nn, gdzie MM odpowiada wartości pakietu SDK, a nn to wartość prywatna przechowywana w  /platform/system/sepolicy.. Przykładowo: 19.0 dla Kitkat, 21.0 dla Lollipop, 22.0 dla Lollipop-MR1, 23.0 dla Marshmallow, 24.0 dla Nougat, 25.0 dla Nougat-MR1, 26.0 dla Oreo, 27.0 dla Oreo-MR1 i 28.0 dla Androida 9. Przewidywania nie zawsze są liczbami całkowitymi. Jeśli na przykład przejście na nową wersję w ramach MR wymaga wprowadzenia niezgodnych zmian w system/sepolicy/public, ale nie w interfejsie API, wersja sepolicy może być taka: vN.1. Wersja w gałęzi rozwojowej jest wersją, która nigdy nie powinna być używana na urządzeniach produkcyjnych 10000.0.

Android może wycofać najstarszą wersję podczas aktualizacji. Aby określić, kiedy wycofać wersję, Android może zbierać informacje o liczbie urządzeń z zasadami dostawcy, na których działa ta wersja Androida i które nadal otrzymują główne aktualizacje platformy. Jeśli liczba jest mniejsza od określonego progu, wersja jest wycofana.

Wpływ na skuteczność wielu atrybutów

Jak opisano na stronie https://github.com/SELinuxProject/cil/issues/9, duża liczba atrybutów przypisanych do typu powoduje problemy z wydajnością w przypadku braku pamięci podręcznej zasad.

Potwierdzono, że jest to problem z Androidem, więc wprowadziliśmy zmiany w Androidzie 8.0, aby usunąć atrybuty dodane do zasad przez kompilator zasad, a także nieużywane atrybuty. Te zmiany rozwiązały problemy z regresją wydajności.

system_ext public and product public policy

Od Androida 11 partycje system_extproduct mogą eksportować swoje wyznaczone typy publiczne do partycji dostawcy. Podobnie jak w przypadku publicznych zasad platformy, dostawca używa typów i reguł automatycznie przekształcanych w atrybuty z wersją, np. z type na type_N, gdzie N to wersja platformy, na której zbudowano partycję dostawcy.

Gdy partycje system_extproduct są oparte na tej samej wersji platformy (N), system kompilacji generuje pliki mapowania podstawowego do plików system_ext/etc/selinux/mapping/N.cilproduct/etc/selinux/mapping/N.cil, które zawierają mapowania tożsamości z poziomu type do type_N. Dostawca może uzyskać dostęp do atrybutu type za pomocą atrybutu z wersją type_N.

Jeśli tylko partycje system_extproduct zostaną zaktualizowane, np. z N na N+1 (lub nowszą), a dostawca pozostanie na wersji N, może utracić dostęp do typów partycji system_extproduct. Aby zapobiec uszkodzeniom, partycje system_ext i product powinny zawierać pliki mapowania plików konkretnych typów na atrybuty type_N. Każdy partner jest odpowiedzialny za utrzymywanie plików mapowania, jeśli zamierza obsługiwać dostawcę N z wersją N+1 (lub nowszą) z partycjami system_extproduct.

Aby to osiągnąć, partnerzy muszą:

  1. Skopiuj wygenerowane pliki mapowania bazy z partycji N, system_extproduct do drzewa źródłowego.
  2. W razie potrzeby zmodyfikuj pliki mapowania.
  3. Zainstaluj pliki mapowania na partycjach N+1 (lub nowszych) system_ext i product.

Załóżmy na przykład, że N system_ext ma jeden publiczny typ o nazwie foo_type. W tym przypadku system_ext/etc/selinux/mapping/N.cil na partycji N system_ext będzie wyglądać tak:

(typeattributeset foo_type_N (foo_type))
(expandtypeattribute foo_type_N true)
(typeattribute foo_type_N)

Jeśli bar_type zostanie dodany do N+1 system_ext i bar_type zostanie zmapowany na foo_type dla dostawcy N, N.cil można zaktualizować z

(typeattributeset foo_type_N (foo_type))

to

(typeattributeset foo_type_N (foo_type bar_type))

a następnie zainstalowane na partycji N+1 system_ext. Dostawca N może nadal uzyskiwać dostęp do funkcji foo_type system_extfoo_typebar_type.N+1

Oznaczanie kontekstów SELinux

Aby umożliwić rozróżnianie polityki zabezpieczeń platformy i zabezpieczeń dostawcy, system tworzy pliki kontekstu SELinux w inny sposób, aby zachować ich odrębność.

konteksty plików,

W Androidzie 8.0 wprowadzono następujące zmiany dotyczące file_contexts:

  • Aby uniknąć dodatkowego obciążenia kompilacją na urządzeniu podczas uruchamiania, file_contexts przestają istnieć w postaci binarnej. Zamiast tego są to czytelne pliki tekstowe z wyrażeniami regularnymi, takie jak {property, service}_contexts (jak w wersji 7.0 i wcześniejszych).
  • file_contexts są podzielone na 2 pliki:
    • plat_file_contexts
      • platforma Android file_context, która nie ma etykiet związanych z urządzeniem, z wyjątkiem etykiet części partycji /vendor, które muszą być dokładnie opisane, aby zapewnić prawidłowe działanie plików sepolicy;
      • Musi znajdować się na partycji system na urządzeniu /system/etc/selinux/plat_file_contexts i być wczytywany przez init na początku wraz z dostawcą file_context.
    • vendor_file_contexts
      • file_context dla danego urządzenia utworzone przez połączenie file_contexts z katalogów wskazywanych przez BOARD_SEPOLICY_DIRS w plikach Boardconfig.mk na urządzeniu.
      • Musi być zainstalowany w miejscu /vendor/etc/selinux/vendor_file_contexts w partycji vendor i wczytany przez init na początku razem z platformą file_context.

Konteksty obiektów

W Androidzie 8.0 property_contexts jest podzielony na 2 pliki:

  • plat_property_contexts
    • platforma Android property_context, która nie ma etykiet dla poszczególnych urządzeń;
    • Musi znajdować się w partycji system/system/etc/selinux/plat_property_contexts i być wczytywany przez init na początku razem z dostawcąproperty_contexts.
  • vendor_property_contexts
    • property_context dla danego urządzenia utworzone przez połączenie property_contexts z katalogów wskazywanych przez BOARD_SEPOLICY_DIRS w plikach Boardconfig.mk na urządzeniu.
    • Musi znajdować się w partycji vendor/vendor/etc/selinux/vendor_property_contexts i być wczytywany przez init na początku wraz z platformą property_context.

Konteksty usług

W Androidzie 8.0 service_contexts jest podzielony na te pliki:

  • plat_service_contexts
    • service_context na platformie Androida w przypadku servicemanager. service_context nie ma etykiet związanych z urządzeniem.
    • Musi znajdować się w partycji system/system/etc/selinux/plat_service_contexts i być wczytywany przez servicemanager na początku razem z dostawcą service_contexts.
  • vendor_service_contexts
    • service_context dla danego urządzenia utworzone przez połączenie service_contexts z katalogów wskazywanych przez BOARD_SEPOLICY_DIRS w plikach Boardconfig.mk urządzenia.
    • Musi znajdować się w partycji vendor w czasie /vendor/etc/selinux/vendor_service_contexts i być wczytywany przez servicemanager na początku razem z platformą service_contexts.
    • Chociaż servicemanager szuka tego pliku podczas uruchamiania, w przypadku w pełni zgodnego urządzenia TREBLE plik vendor_service_contexts NIE MOŻE istnieć. Dzieje się tak, ponieważ wszystkie interakcje między procesami vendor i system muszą przechodzić przez procesy hwservicemanager/hwbinder.
  • plat_hwservice_contexts
    • Platforma Android hwservice_context dla hwservicemanager, która nie ma etykiet związanych z urządzeniem.
    • Musi znajdować się w partycji system w czasie /system/etc/selinux/plat_hwservice_contexts i być wczytywana przez hwservicemanager na początku razem z vendor_hwservice_contexts.
  • vendor_hwservice_contexts
    • hwservice_context dla danego urządzenia utworzone przez połączenie hwservice_contexts z katalogów wskazywanych przez BOARD_SEPOLICY_DIRS w plikach Boardconfig.mk urządzenia.
    • Musi znajdować się w partycji vendor/vendor/etc/selinux/vendor_hwservice_contexts i być wczytywany przez hwservicemanager na początku razem z plat_service_contexts.
  • vndservice_contexts
    • service_context dla urządzenia vndservicemanager utworzone przez połączenie vndservice_contexts znajdujących się w katalogach wskazywanych przez BOARD_SEPOLICY_DIRSBoardconfig.mk urządzenia.
    • Plik musi znajdować się na partycji vendor w miejscu /vendor/etc/selinux/vndservice_contexts i na początku musi być wczytywany przez vndservicemanager.

Konteksty Seapp

W Androidzie 8.0 seapp_contexts jest podzielony na 2 pliki:

  • plat_seapp_contexts
    • platforma Android seapp_context bez zmian specyficznych dla urządzenia.
    • Musi znajdować się w partycji system w czasie /system/etc/selinux/plat_seapp_contexts.
  • vendor_seapp_contexts
    • Rozszerzenie dla konkretnego urządzenia na platformie seapp_context utworzone przez połączenie seapp_contexts znalezionego w katalogach wskazywanych przez BOARD_SEPOLICY_DIRS w plikach Boardconfig.mk urządzenia.
    • Musi znajdować się na partycji vendor w czasie /vendor/etc/selinux/vendor_seapp_contexts.

Uprawnienia MAC

W Androidzie 8.0 mac_permissions.xml jest podzielony na 2 pliki:

  • Platforma: mac_permissions.xml
    • platforma Android mac_permissions.xml bez zmian specyficznych dla urządzenia.
    • Musi znajdować się w partycji system w czasie /system/etc/selinux/.
  • Nie na platformie mac_permissions.xml
    • Rozszerzenie dla konkretnego urządzenia na platformie mac_permissions.xml utworzone na podstawie pliku mac_permissions.xml znajdującego się w katalogach wskazywanych przez element BOARD_SEPOLICY_DIRS w plikach Boardconfig.mk urządzenia.
    • Musi znajdować się w partycji vendor w czasie /vendor/etc/selinux/.