Z tego artykułu dowiesz się, jak Android obsługuje problemy z zgodnością zasad z aktualizacjami oprogramowania OTA, w których nowe ustawienia SELinux mogą różnić się od starych ustawień SELinux dostawcy.
Projektowanie zasad SELinux na podstawie Treble uwzględnia binarne rozróżnienie między zasadami platformy a dostawcy. Schemat staje się bardziej skomplikowany, jeśli partycje dostawcy generują zależności, takie jak platform < vendor < oem.
W Androidzie 8.0 i nowszych zasada 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 każdej 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ć również używane bezpośrednio w decyzji dotyczącej 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 powoduje to zmiany zachowania gwarantowanego przez zasady dotyczące platformy w poprzedniej wersji. Mapowanie jest aktualizowane przez utrzymywanie aktualnego pliku mapowania dla każdej wersji platformy, który zawiera informacje o przynależności atrybutów do każdego typu wyeksportowanego w zasadach publicznych.
Własność obiektu i oznaczanie
Podczas dostosowywania zasad w Androidzie 8.0 lub nowszym 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 kolizje mogą dotyczyć też nazw typów i 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 podwójnymi 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 nieruchomości | 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.dla 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 platforma, jak i dostawca 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, które nie są egzekwowane technicznie. 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
|
Wszystkie 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 przez neverallows):
vendor_filemusi być domyślną etykietą wszystkich plików na partycjivendor. Zasady platformy wymagają tego, aby uzyskać dostęp do implementacji przepustki HAL.- Wszystkie nowe
exec_typesdodane w partycjivendorza pomocą SEPolicy dostawcy muszą mieć atrybutvendor_file_type. Jest to wymuszane za pomocą reguł neverallows. - Aby uniknąć konfliktów z przyszłymi aktualizacjami platformy lub platformy, nie oznaczaj plików innymi niż
exec_typesw partycjivendor. - Wszystkie zależności bibliotek dla identyfikowanych przez AOSP interfejsów HAL 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ć typu ogólnego proc, aby dodać reguły dla domen dostawców. 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ą sysfswę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 etykietować tylko pliki w /dev/vendor (na przykład /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 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ą genfscon w system/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/udcjest domyślnie oznaczony jakosysfs. -
Od poziomu interfejsu API 202504 dostawcy
/sys/class/udcma 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ć większa lub równa poziomowi 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 wdrożyć mechanizmy zastępcze w celu zapewnienia zgodności. Platforma może używać bibliotek dostępnych tylko na danej platformie, aby zapytać o wersję etykiet genfs.
-
W przypadku elementów natywnych użyj właściwości
libgenfslabelsversion. Plik nagłówkalibgenfslabelsversionznajdziesz w folderzegenfslabelsversion.h. -
W Javie użyj:
android.os.SELinux.getGenfsLabelsVersion().
Atrybuty zgodności
Zasady SELinux to interakcja między typami źródła i docelowego 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. Na 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 źródłowemu typ, który ma atrybut odpowiadający zasadom zarówno 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 zasad:
- 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 opierał się 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 elementami. Zarówno platformy, jak i dostawcy mogą nadal pisać zasady w obecnej formie.
Zasady publiczne na platformie wyeksportowane jako allow source_foo target_bar:class
perm; są uwzględnione w ramach zasad dostawcy. Podczas kompilacji (która obejmuje odpowiednią wersję) jest on przekształcany w zasady, które zostaną przekazane do części urządzenia należącej do dostawcy (wyświetlane w przekształconym wspólnym języku pośrednim [CIL]):
(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 ich typy są objęte tą polityką oraz jakie są zasady dotyczące atrybutów 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 docelownika. Można to zobaczyć w przypadku /dev/binder, który jest oznaczony jako binder_device we wszystkich wersjach. W przekształconej zasadach 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 będzie 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/Azostała zmieniona zsysfsnasysfs_A). Kod dostawcy opiera się na regule umożliwiającej dostęp do atrybutusysfsi 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, jest nowy, zmiana etykiety przebiega tak samo jak w przypadku nowego typu, z tą różnicą, że jeśli używana jest istniejąca etykieta, dodanie starego typu atrybutu spowoduje, że inne obiekty z tą etykietą również staną się dostępne. Tak właśnie działa platforma, a uznaliśmy, że jest to akceptowalny kompromis, który pozwala zachować zgodność.
(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 występuje, 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 usuwamy 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 dodaj 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 urządzenia uruchamiane z Androidem 9 nie mogą ich używać.
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ędzyvendoracoredomains. 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.
- Kod dostawcy powinien zawierać
system_executes_vendor_violators.Atrybut dla wszystkich domen systemowych (z wyjątkieminitishell 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, a tym samym przestać byćcoredomain.
- Takie zależności platformy od plików binarnych dostawcy muszą być zaimplementowane za pomocą interfejsów HIDL HAL.
Atrybuty o niesprawdzonej tożsamości
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:
- 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ę.
- Serwery HAL (podzbiór usług HwBinder) zawierają kod, który częściej powoduje problemy z bezpieczeństwem niż komponenty
system/core, a także mają 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łudzesurfaceflingerBinder, do której aplikacje mogą uzyskać dostęp.hal_omx_hwservice. Jest to wersja usługi Bindermediacodecw ramach HwBinder, do której aplikacje mogą uzyskać dostęp.hal_codec2_hwservice. Jest to nowsza wersja programuhal_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 niezaufanym aplikacjom należy umożliwić komunikację z usługą systemową, która komunikuje się z interfejsem HIDL dostawcy. Aplikacje mogą na przykład komunikować się z
binderservicedomain, a następnie zmediaserver(który jestbinderservicedomain), a ten z kolei zhal_graphics_allocator.LUB
- Aplikacje, które wymagają bezpośredniego dostępu do interfejsów
vendorHAL, 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 połączeniem 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ż same atrybuty nie mają wersji). Platforma odpowiada 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 oznaczone 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 wymaga wprowadzenia zmian 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 jest uruchomiona 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_ext i product 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_ext i product są oparte na tej samej wersji platformy (N), system kompilacji generuje pliki mapowania podstawowego do plików system_ext/etc/selinux/mapping/N.cil i product/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_ext i product 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_ext i product. 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_ext i product.
Aby to osiągnąć, partnerzy muszą:
- Skopiuj wygenerowane pliki mapowania bazy z partycji
Nsystem_extiproductdo ich źródeł w drzewie. - W razie potrzeby zmodyfikuj pliki mapowania.
-
Zainstaluj pliki mapowania na partycjach
system_extiproductsystemuN+1(lub nowszego).
Załóżmy na przykład, że N system_ext ma jeden publiczny typ o nazwie foo_type. W przypadku tego dysku system_ext/etc/selinux/mapping/N.cilw 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 atrybut bar_type zostanie dodany do elementu N+1 system_ext, a atrybut bar_type powinien zostać zmapowany na atrybut foo_type dla dostawcy N, atrybut N.cil można zaktualizować za pomocą
(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 i bar_type w systemie N+1system_ext.
Oznaczanie kontekstów SELinux
Aby umożliwić rozróżnienie 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_contextsprzestają istnieć w postaci binarnej. Zamiast tego są to czytelne pliki tekstowe z wyrażeniami regularnymi, takie jak{property, service}_contexts(takie jak w wersji 7.0 i wcześniejszych). file_contextssą 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
systemna urządzeniu/system/etc/selinux/plat_file_contextsi być wczytywany przezinitna początku wraz z dostawcąfile_context.
- platforma Android
vendor_file_contextsfile_contextdla danego urządzenia utworzone przez połączeniefile_contextsznalezione w katalogach wskazywanych przezBOARD_SEPOLICY_DIRSw plikachBoardconfig.mkurządzenia.- Musi być zainstalowany w miejscu
/vendor/etc/selinux/vendor_file_contextsw partycjivendori wczytany przezinitna początku razem z platformąfile_context.
Konteksty obiektu
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
systemw/system/etc/selinux/plat_property_contextsi być wczytywany przezinitna początku razem z dostawcąproperty_contexts.
- platforma Android
vendor_property_contextsproperty_contextdla danego urządzenia utworzone przez połączenieproperty_contextsz katalogów wskazywanych przezBOARD_SEPOLICY_DIRSw plikachBoardconfig.mkurządzenia.- Musi znajdować się w partycji
vendorw/vendor/etc/selinux/vendor_property_contextsi być wczytywany przezinitna początku razem z platformąproperty_context.
Konteksty usług
W Androidzie 8.0 service_contexts jest podzielony na te pliki:
plat_service_contextsservice_contextna platformie Androida w przypadkuservicemanager.service_contextnie ma etykiet związanych z urządzeniem.- Musi znajdować się w partycji
systemw/system/etc/selinux/plat_service_contextsi być wczytywany przezservicemanagerna początku razem z dostawcąservice_contexts.
vendor_service_contextsservice_contextdla danego urządzenia utworzone przez połączenieservice_contextsz katalogów wskazywanych przezBOARD_SEPOLICY_DIRSw plikachBoardconfig.mkurządzenia.- Musi znajdować się w partycji
vendorw czasie/vendor/etc/selinux/vendor_service_contextsi być wczytywany przezservicemanagerna początku razem z platformąservice_contexts. - Chociaż
servicemanagerszuka tego pliku podczas uruchamiania, w przypadku w pełni zgodnego urządzeniaTREBLEplikvendor_service_contextsNIE MOŻE istnieć. Dzieje się tak, ponieważ wszystkie interakcje między procesamivendorisystemmuszą przechodzić przez proceshwservicemanager/hwbinder.
plat_hwservice_contexts- Platforma Android
hwservice_contextdlahwservicemanager, która nie ma etykiet związanych z urządzeniem. - Musi znajdować się w partycji
systemw/system/etc/selinux/plat_hwservice_contextsi być wczytywana przezhwservicemanagerna początku razem zvendor_hwservice_contexts.
- Platforma Android
vendor_hwservice_contextshwservice_contextdla danego urządzenia utworzone przez połączeniehwservice_contextsz katalogów wskazywanych przezBOARD_SEPOLICY_DIRSw plikachBoardconfig.mkurządzenia.- Musi znajdować się w partycji
vendorw/vendor/etc/selinux/vendor_hwservice_contextsi być wczytywana przezhwservicemanagerna początku razem zplat_service_contexts.
vndservice_contextsservice_contextdla urządzeniavndservicemanagerutworzone przez połączenievndservice_contextsznajdujących się w katalogach wskazywanych przezBOARD_SEPOLICY_DIRSwBoardconfig.mkurządzenia.- Plik musi znajdować się na partycji
vendorw miejscu/vendor/etc/selinux/vndservice_contextsi być wczytywany na początku przez funkcjęvndservicemanager.
Konteksty Seapp
W Androidzie 8.0 seapp_contexts jest podzielony na 2 pliki:
plat_seapp_contexts- platforma Android
seapp_contextbez zmian specyficznych dla urządzenia. - Musi znajdować się w partycji
systemw miejscu/system/etc/selinux/plat_seapp_contexts.
- platforma Android
vendor_seapp_contexts- Rozszerzenie na potrzeby konkretnego urządzenia do platformy
seapp_contextutworzone przez połączenieseapp_contextsznalezionego w katalogach wskazywanych przezBOARD_SEPOLICY_DIRSw plikachBoardconfig.mkurządzenia. - Musi znajdować się w partycji
vendorw/vendor/etc/selinux/vendor_seapp_contexts.
- Rozszerzenie na potrzeby konkretnego urządzenia do platformy
Uprawnienia MAC
W Androidzie 8.0 mac_permissions.xml jest podzielony na 2 pliki:
- Platforma:
mac_permissions.xml- platforma Android
mac_permissions.xmlbez zmian specyficznych dla urządzenia. - Musi znajdować się w partycji
systemw miejscu/system/etc/selinux/.
- platforma Android
- Nie na platformie
mac_permissions.xml- Rozszerzenie dla konkretnego urządzenia na platformę
mac_permissions.xmlutworzone na podstawie plikumac_permissions.xmlznajdującego się w katalogach wskazywanych przez elementBOARD_SEPOLICY_DIRSw plikachBoardconfig.mkurządzenia. - Musi znajdować się w partycji
vendorw miejscu/vendor/etc/selinux/.
- Rozszerzenie dla konkretnego urządzenia na platformę