Zgodność z zasadami

Na tej stronie opisujemy, jak Android radzi sobie z problemami ze zgodnością zasad podczas aktualizacji platformy OTA, gdy nowe ustawienia SELinux platformy mogą różnić się od starych ustawień SELinux dostawcy.

Własność obiektów i oznaczanie ich etykietami

Własność każdego obiektu musi być jasno określona, aby zachować rozdzielenie zasad platformy i zasad dostawcy. Jeśli na przykład w kolejnej aktualizacji OTA etykiety zasad dostawcy /dev/foo i etykiety zasad platformy /dev/foo są różne, wystąpi nieokreślone zachowanie, np. nieoczekiwane odrzucenie lub, co gorsza, błąd rozruchu. W przypadku SELinux objawia się to jako kolizja etykiet. Węzeł urządzenia może mieć tylko jedną etykietę, która jest ostatnią zastosowaną etykietą. W rezultacie:

  • Procesy, które potrzebują dostępu do etykiety, której nie udało się zastosować, tracą dostęp do zasobu.
  • Procesy, które uzyskują dostęp do pliku, mogą ulec awarii, ponieważ utworzono nieprawidłowy węzeł urządzenia.

Kolizje między etykietami platformy i dostawcy mogą wystąpić w przypadku dowolnego obiektu, który ma etykietę SELinux, w tym właściwości, usług, procesów, plików i gniazd. Aby uniknąć tych problemów, wyraźnie określ, kto jest właścicielem tych obiektów.

Przestrzeń nazw typów i atrybutów

Oprócz kolizji etykiet mogą też wystąpić kolizje nazw typów i atrybutów SELinux. SELinux nie zezwala na wielokrotne deklaracje tych samych typów i atrybutów. Zasady z powtarzającymi się deklaracjami nie zostaną skompilowane. Aby uniknąć kolizji nazw typów i nazw atrybutów, zalecamy, aby wszystkie deklaracje dostawców zaczynały się od prefiksu vendor_. Na przykład sprzedawcy powinni używać znacznika type vendor_foo, domain; zamiast type foo, domain;.

Własność pliku

Zapobieganie kolizjom w przypadku plików jest trudne, ponieważ zasady platformy i dostawcy zwykle zapewniają etykiety dla wszystkich systemów plików. W przeciwieństwie do nazewnictwa typów, przestrzenie nazw plików nie są praktyczne, ponieważ wiele z nich jest tworzonych przez jądro. Aby zapobiec takim kolizjom, postępuj zgodnie z wytycznymi dotyczącymi nazewnictwa systemów plików podanymi w tej sekcji. W przypadku Androida 8.0 są to zalecenia bez egzekwowania technicznego. W przyszłości te rekomendacje będą egzekwowane przez pakiet testów dostawcy (VTS).

System (/system)

Tylko obraz systemu musi zawierać etykiety komponentów /system, file_contexts, service_contexts itp. Jeśli etykiety komponentów /system zostaną dodane w zasadach dostawcy, aktualizacja OTA obejmująca tylko platformę może nie być możliwa.

Dostawca (/vendor)

Zasady SELinux w AOSP już oznaczają części partycji vendor, z którymi platforma wchodzi w interakcje, co umożliwia pisanie 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:

/vendor path Etykieta dostarczona przez platformę Procesy platformy w zależności od etykiety
/vendor(/.*)? vendor_file Wszyscy klienci HAL w platformie, ueventd itp.
/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ł (egzekwowanych za pomocą neverallows):

  • vendor_file musi być domyślną etykietą dla wszystkich plików w vendor partycji. Zasady platformy wymagają tego, aby uzyskać dostęp do implementacji HAL przekazywania.
  • Wszystkie nowe exec_types dodane w vendor partycji za pomocą zasad dostawcy muszą mieć atrybut vendor_file_type. Jest to egzekwowane za pomocą reguł neverallow.
  • Aby uniknąć konfliktów z przyszłymi aktualizacjami platformy lub struktury, nie oznaczaj plików innych niż exec_types w partycji vendor.
  • Wszystkie zależności biblioteki w przypadku zidentyfikowanych przez AOSP interfejsów HAL działających w tym samym procesie muszą być oznaczone jako same_process_hal_file..

Procfs (/proc)

Pliki w /proc można oznaczać tylko etykietą genfscon. W Androidzie 7.0 zarówno zasady platformy, jak i zasady dostawcy używały genfscon do oznaczania plików w procfs.

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

Debugfs (/sys/kernel/debug)

Debugfs może być oznaczona w file_contextsgenfscon. W Androidzie 7.0–10 zarówno etykieta platformy, jak i etykieta dostawcy debugfs.

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ć oznaczona w file_contextsgenfscon. W Androidzie 7.0 tylko etykiety platformytracefs.

Rekomendacja: tylko platforma może oznaczać tracefs.

Sysfs (/sys)

Pliki w /sys mogą być oznaczane etykietami za pomocą file_contexts i genfscon. W Androidzie 7.0 zarówno platforma, jak i dostawca używają genfscon do oznaczania plików w sysfs.

Rekomendacja: platforma może oznaczać sysfswęzły, które nie są specyficzne dla urządzenia. W przeciwnym razie tylko dostawca może oznaczać pliki.

tmpfs (/dev)

Pliki w folderze /dev mogą być oznaczone etykietami w folderze file_contexts. W Androidzie 7.0 zarówno platforma, jak i dostawca mają tutaj pliki etykiet.

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

Rootfs (/)

Pliki w folderze / mogą być oznaczone etykietami w folderze file_contexts. W Androidzie 7.0 pliki etykiet platformy i dostawcy znajdują się tutaj.

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

Dane (/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

Począwszy 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 vendor. Dzięki temu starszevendor partycje mogą zachować dotychczasową implementację SEPolicy. Jest to kontrolowane przez zmienną pliku Makefile BOARD_GENFS_LABELS_VERSION, która jest przechowywana w /vendor/etc/selinux/genfs_labels_version.txt.

Przykład:

  • W przypadku interfejsu API dostawcy na poziomie 202404 węzeł /sys/class/udc jest domyślnie oznaczony etykietą sysfs.
  • Od poziomu interfejsu API dostawcy 202504 parametr /sys/class/udc jest oznaczony jako sysfs_udc.

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

BOARD_GENFS_LABELS_VERSION może być równa poziomowi interfejsu API dostawcy lub od niego większa. Na przykład vendorpartycje korzystające z poziomu interfejsu API 202404 mogą ustawić wartość BOARD_GENFS_LABELS_VERSION na 202504, aby zastosować nowe etykiety wprowadzone w poziomie 202504. Zobacz listę etykiet genfs dotyczących 202504.

Podczas etykietowania węzłów genfscon platforma musi uwzględniać starsze partycje vendor i w razie potrzeby wdrażać mechanizmy rezerwowe zapewniające zgodność. Platforma może używać bibliotek dostępnych tylko na platformie do wysyłania zapytań o wersję etykiet genfs.

Platforma – polityka publiczna

Polityka SELinux platformy jest podzielona na część prywatną i publiczną. Zasady publiczne platformy składają się z typów i atrybutów, które są zawsze dostępne na poziomie interfejsu API dostawcy, działając jako interfejs API między platformą a dostawcą. Ta zasada jest udostępniana autorom zasad dostawców, aby umożliwić im tworzenie plików zasad dostawców, które w połączeniu z zasadami prywatnymi platformy tworzą w pełni funkcjonalne zasady dotyczące urządzenia. Zasady platformy są zdefiniowane w system/sepolicy/public.

Na przykład typ vendor_init, który reprezentuje proces inicjowania w kontekście dostawcy, jest zdefiniowany w system/sepolicy/public/vendor_init.te:

type vendor_init, domain;

Dostawcy mogą użyć typu vendor_init, aby napisać niestandardowe reguły zasad:

# Allow vendor_init to set vendor_audio_prop in vendor's init scripts
set_prop(vendor_init, vendor_audio_prop)

Atrybuty zgodności

Zasady SELinux to interakcja między typami źródłowymi i docelowymi w przypadku określonych klas obiektów i uprawnień. Każdy obiekt (np. procesy, pliki) objęty zasadami SELinux może mieć tylko 1 typ, ale ten typ może mieć wiele atrybutów.

Zasady są w większości sformułowane w odniesieniu do istniejących typów. W tym przypadku zarówno vendor_init, jak i debugfs są typami:

allow vendor_init debugfs:dir { mounton };

Działa to dlatego, że 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 zmieni się tylko w jednych z tych zasad, w drugich może wystąpić zasada, która wcześniej zyskała lub utraciła dostęp. Załóżmy na przykład, że etykiety zasad platformy oznaczają węzły sysfs jako sysfs:

/sys(/.*)? u:object_r:sysfs:s0

Zasady dostawcy zapewniają dostęp do /sys/usb oznaczonego jakosysfs:

allow vendor_init sysfs:chr_file rw_file_perms;

Jeśli zasady platformy zostaną zmienione tak, aby oznaczać /sys/usb jako sysfs_usb, zasady dostawcy pozostaną bez zmian, ale vendor_init utraci dostęp do /sys/usb z powodu braku zasad dotyczących nowego typu sysfs_usb:

/sys/usb u:object_r:sysfs_usb:s0

Aby rozwiązać ten problem, Android wprowadza koncepcję atrybutów z określoną wersją. Podczas kompilacji system kompilacji automatycznie tłumaczy publiczne typy platformy używane w zasadach dostawcy na te atrybuty z określoną wersją. To tłumaczenie jest możliwe dzięki plikom mapowania, które łączą atrybut z wersją z co najmniej 1 publicznym typem z platformy.

Załóżmy na przykład, że w zasadach platformy 202504 element /sys/usb jest oznaczony jako sysfs, a zasady dostawcy 202504 przyznają vendor_init dostęp do /sys/usb. W tej sytuacji:

  • Zasady dostawcy tworzą regułę allow vendor_init sysfs:chr_file rw_file_perms;, ponieważ /sys/usb jest oznaczony jako sysfs w zasadach platformy 202504. Gdy system kompilacji skompiluje zasady dostawcy, automatycznie przetłumaczy regułę na allow vendor_init_202504 sysfs_202504:chr_file rw_file_perms;. Atrybuty vendor_init_202504sysfs_202504 odpowiadają typom vendor_initsysfs, które są typami zdefiniowanymi przez platformę.
  • System kompilacji generuje plik mapowania tożsamości /system/etc/selinux/mapping/202504.cil. Ponieważ partycje systemvendor korzystają z tej samej wersji 202504, plik mapowania zawiera mapowania tożsamości z type_202504 na type. Na przykład:vendor_init_202504 jest mapowany na vendor_init, a sysfs_202504 jest mapowany na sysfs:
    (typeattributeset sysfs_202504 (sysfs))
    (typeattributeset vendor_init_202504 (vendor_init))
    ...

Gdy wersja zostanie zmieniona z 202504 na 202604, w system/sepolicy/private/compat/202504/202504.cil zostanie utworzony nowy plik mapowania dla partycji 202504 vendor, który zostanie zainstalowany w /system/etc/selinux/mapping/202504.cil w przypadku partycji 202604 lub nowszych system. Początkowo ten plik mapowania zawiera mapowania tożsamości opisane wcześniej. Jeśli do zasad platformy 202604 zostanie dodana nowa etykieta sysfs_usb dla /sys/usb, plik mapowania zostanie zaktualizowany, aby zmapować sysfs_202504 na sysfs_usb:

(typeattributeset sysfs_202504 (sysfs sysfs_usb))
(typeattributeset vendor_init_202504 (vendor_init))
...

Ta aktualizacja umożliwia przekonwertowanej regule zasad dostawcy allow vendor_init_202504 sysfs_202504:chr_file rw_file_perms; automatyczne przyznawanie dostępu vendor_init do nowego typu sysfs_usb.

Aby zachować zgodność ze starszymi partycjami vendor, za każdym razem, gdy dodawany jest nowy typ publiczny, musi on być mapowany na co najmniej jeden z atrybutów z określoną wersją w pliku mapowania system/sepolicy/private/compat/ver/ver.cil lub musi być wymieniony w sekcji system/sepolicy/private/compat/ver/ver.ignore.cil, aby wskazać, że w poprzednich wersjach dostawcy nie ma pasującego typu.

Połączenie zasad platformy, zasad dostawcy i pliku mapowania umożliwia aktualizację systemu bez aktualizowania zasad dostawcy. Konwersja na atrybuty z określoną wersją odbywa się automatycznie, więc zasady dostawcy nie muszą uwzględniać obsługi wersji i mogą nadal używać typów publicznych w niezmienionej postaci.

system_ext public and product public policy

Od Androida 11 partycje system_extproduct mogą eksportować wyznaczone typy publiczne do partycji vendor. Podobnie jak w przypadku zasad publicznych platformy, zasady dostawcy korzystają z typów i reguł automatycznie tłumaczonych na atrybuty z wersjami, np. z type na type_ver, gdzie ver to poziom interfejsu API dostawcy w vendor partycji.

Gdy partycje system_extproduct są oparte na tej samej wersji platformy ver, system kompilacji generuje podstawowe pliki mapowania do system_ext/etc/selinux/mapping/ver.cilproduct/etc/selinux/mapping/ver.cil, które zawierają mapowania tożsamości z type na type_ver. Zasady dostawcy mogą uzyskać dostęp do type za pomocą atrybutu z określoną wersją type_ver.

Jeśli zaktualizowane zostaną tylko partycje system_extproduct, np. z ver na ver+1 (lub nowszą), a partycja vendor pozostanie na poziomie ver, zasady dostawcy mogą utracić dostęp do typów partycji system_extproduct. Aby zapobiec przerwaniu, partycje system_extproduct powinny udostępniać pliki mapowania z konkretnych typów na atrybuty type_ver. Każdy partner jest odpowiedzialny za utrzymywanie plików mapowania, jeśli obsługuje partycję ver vendorver+1 (lub nowszą) system_ext i partycje product.

Aby zainstalować pliki mapowania na partycjach system_extproduct, producenci urządzeń lub dostawcy powinni:

  1. Skopiuj wygenerowane podstawowe pliki mapowania z partycji ver system_extproduct do drzewa źródłowego.
  2. W razie potrzeby zmień pliki mapowania.
  3. Zainstaluj pliki mapowania na partycjach ver+1 (lub nowszych) system_extproduct.

Załóżmy na przykład, że partycja 202504 system_ext ma jeden typ publiczny o nazwie foo_type. W takim przypadku system_ext/etc/selinux/mapping/202504.cil partycja 202504 system_ext wygląda tak:

(typeattributeset foo_type_202504 (foo_type))
(expandtypeattribute foo_type_202504 true)
(typeattribute foo_type_202504)

Jeśli do partycji 202604 system_ext zostanie dodany element bar_type, a element bar_type powinien być mapowany na element foo_type w przypadku partycji 202504 vendor, element 202504.cil można zaktualizować z wartości (typeattributeset foo_type_202504 (foo_type)) na (typeattributeset foo_type_202504 (foo_type bar_type)) i następnie zainstalować w partycji 202604 system_ext. Partycja 202504 vendor może nadal uzyskiwać dostęp do foo_typebar_type partycji 202604 system_ext.

Zmiany atrybutów w Androidzie 9

Urządzenia, które zostaną zaktualizowane do Androida 9, mogą używać tych atrybutów, ale urządzenia z Androidem 9 nie mogą.

Atrybuty naruszającego

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

  • data_between_core_and_vendor_violators. Atrybut wszystkich domen, które naruszają wymaganie dotyczące nieudostępniania plików według ścieżki między vendorcoredomains. Procesy platformy i dostawcy nie powinny używać plików na dysku do komunikacji (niestabilny interfejs ABI). Rekomendacja:
    • Kod dostawcy powinien używać /data/vendor.
    • System nie powinien używać /data/vendor.
  • system_executes_vendor_violators. Atrybut dla wszystkich domen systemowych (z wyjątkiem initshell domains) naruszających wymaganie dotyczące niewykonywania plików binarnych dostawcy. Wykonywanie plików binarnych dostawcy ma niestabilny interfejs API. Platforma nie powinna bezpośrednio wykonywać plików binarnych dostawcy. Rekomendacja:
    • Takie zależności platformy od plików binarnych dostawcy muszą być ukryte za interfejsami HAL HIDL.

      LUB

    • coredomains, które potrzebują dostępu do plików binarnych dostawcy, powinny zostać przeniesione do partycji vendor i tym samym przestać być coredomain.

Nieufne atrybuty

Niezaufane aplikacje, które hostują dowolny kod, nie powinny mieć dostępu do usług HwBinder, z wyjątkiem tych, które są uważane za wystarczająco bezpieczne, aby można było z nich korzystać w takich aplikacjach (patrz bezpieczne usługi poniżej). Główne powody to:

  1. Serwery HwBinder nie przeprowadzają uwierzytelniania klienta, ponieważ HIDL nie udostępnia obecnie informacji o identyfikatorze UID wywołującego. Nawet jeśli HIDL udostępniałby 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 dla bezpieczeństwa domyślnym założeniem jest to, że każda usługa HwBinder traktuje wszystkich swoich klientów jako równie uprawnionych do wykonywania operacji oferowanych przez tę usługę.
  2. Serwery HAL (podzbiór usług HwBinder) zawierają kod, w którym występuje większa częstotliwość występowania problemów z bezpieczeństwem niż w komponentach system/core. Mają też dostęp do niższych warstw stosu (aż do sprzętu), co zwiększa możliwości obejścia modelu zabezpieczeń Androida.

Usługi związane z sejfami

Bezpieczne usługi obejmują:

  • same_process_hwservice. Te usługi (z definicji) działają w procesie klienta, a tym samym mają taki sam dostęp jak domena klienta, w której działa proces.
  • coredomain_hwservice. Te usługi nie stwarzają zagrożeń związanych z przyczyną nr 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 mają dostęp.
  • hal_omx_hwservice. Jest to wersja HwBinder usługi Binder mediacodec, do której aplikacje mają dostęp.
  • hal_codec2_hwservice. To nowsza wersja usługi hal_omx_hwservice.

Atrybuty, których można używać

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.

Zalecenia:

  • Niezaufane aplikacje powinny komunikować się z usługą systemową, która komunikuje się z interfejsem HAL HIDL dostawcy. Na przykład aplikacje mogą komunikować się z binderservicedomain, a potem z mediaserver (który jest binderservicedomain), który z kolei komunikuje się z hal_graphics_allocator.

    LUB

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

Testy atrybutów plików

Android 9 zawiera testy czasu 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).

Oznaczanie kontekstów SELinux

Aby rozróżnić zasady SELinux platformy i dostawcy, system tworzy pliki kontekstu SELinux w inny sposób, aby je od siebie oddzielić.

Konteksty plików

W Androidzie 8.0 wprowadzono te zmiany dotyczące file_contexts:

  • Aby uniknąć dodatkowych obciążeń związanych z kompilacją na urządzeniu podczas uruchamiania, file_contexts nie będą one już istniały w formie binarnej. Zamiast tego są to czytelne pliki tekstowe z wyrażeniami regularnymi, takie jak {property, service}_contexts (jak przed wersją 7.0).
  • file_contexts są podzielone na 2 pliki:
    • plat_file_contexts
      • Platforma Androidfile_context, która nie ma etykiet specyficznych dla urządzenia, z wyjątkiem etykietowania części partycji /vendor, które musi być precyzyjne, aby zapewnić prawidłowe działanie plików sepolicy.
      • Musi znajdować się w system na urządzeniu i być wczytywana przez init na początku wraz z file_context dostawcy./system/etc/selinux/plat_file_contexts
    • vendor_file_contexts
      • file_context – tworzony przez połączenie file_contexts znalezionych w katalogach wskazanych przez BOARD_SEPOLICY_DIRS w plikach Boardconfig.mk urządzenia.
      • Musi być zainstalowany w /vendor/etc/selinux/vendor_file_contexts na partycji vendor i ładowany przez init na początku wraz z platformą file_context.

Konteksty usługi

W Androidzie 8.0 property_contexts jest podzielony na 2 pliki:

  • plat_property_contexts
    • platformy Androidproperty_context, która nie ma etykiet przypisanych do konkretnych urządzeń.
    • Musi znajdować się w system partycji w /system/etc/selinux/plat_property_contexts i być wczytywana przez init na początku wraz z property_contexts.
  • vendor_property_contexts
    • property_context – tworzony przez połączenie property_contexts znalezionych w katalogach wskazanych przez BOARD_SEPOLICY_DIRS w plikach Boardconfig.mk urządzenia.
    • Musi znajdować się w partycji vendor/vendor/etc/selinux/vendor_property_contexts i być wczytywana 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_contextna platformę Androidservicemanager. service_context nie ma etykiet przypisanych do urządzenia.
    • Musi znajdować się w system partycji w /system/etc/selinux/plat_service_contexts i być wczytywana przez servicemanager na początku wraz z service_contexts.
  • vendor_service_contexts
    • service_context – tworzone przez połączenie service_contexts znalezionych w katalogach wskazywanych przez BOARD_SEPOLICY_DIRS w plikach Boardconfig.mk urządzenia.
    • Musi znajdować się w partycji vendor pod adresem /vendor/etc/selinux/vendor_service_contexts i być wczytywany przez servicemanager na początku wraz 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 vendorsystem muszą przechodzić przez hwservicemanager/hwbinder.
  • plat_hwservice_contexts
    • platformy Androidhwservice_context,hwservicemanager która nie ma etykiet specyficznych dla urządzenia.
    • Musi znajdować się w partycji system w lokalizacji /system/etc/selinux/plat_hwservice_contexts i być wczytywany przez hwservicemanager na początku razem z vendor_hwservice_contexts.
  • vendor_hwservice_contexts
    • hwservice_context – tworzone przez połączenie hwservice_contexts znalezionych w katalogach wskazywanych przez BOARD_SEPOLICY_DIRS w plikach Boardconfig.mk urządzenia.
    • Musi znajdować się w partycji vendor pod adresem /vendor/etc/selinux/vendor_hwservice_contexts i być wczytywany przez hwservicemanager na początku wraz z plat_service_contexts.
  • vndservice_contexts
    • service_context dla urządzenia vndservicemanager utworzony przez połączenie vndservice_contexts znalezionych w katalogach wskazywanych przez BOARD_SEPOLICY_DIRSBoardconfig.mk urządzenia.
    • Ten plik musi znajdować się w partycji vendor w lokalizacji /vendor/etc/selinux/vndservice_contexts i być wczytywany przez vndservicemanager na początku.

Konteksty Seapp

W Androidzie 8.0 seapp_contexts jest podzielony na 2 pliki:

  • plat_seapp_contexts
    • platformy Androidseapp_context, która nie ma zmian specyficznych dla urządzenia.
    • Musi znajdować się w partycji system/system/etc/selinux/plat_seapp_contexts.
  • vendor_seapp_contexts
    • Rozszerzenie platformy seapp_context specyficzne dla urządzenia, utworzone przez połączenie seapp_contexts znalezionych w katalogach wskazywanych przez BOARD_SEPOLICY_DIRS w plikach Boardconfig.mk urządzenia.
    • Musi znajdować się w partycji vendor/vendor/etc/selinux/vendor_seapp_contexts.

Uprawnienia MAC

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

  • Peron mac_permissions.xml
    • platformy Androidmac_permissions.xml, która nie ma zmian specyficznych dla urządzenia.
    • Musi znajdować się w partycji system/system/etc/selinux/.
  • Poza platformą mac_permissions.xml
    • Rozszerzenie specyficzne dla urządzenia do platformy mac_permissions.xml utworzone na podstawie mac_permissions.xml znalezionych w katalogach wskazywanych przez BOARD_SEPOLICY_DIRS w plikach Boardconfig.mk urządzenia.
    • Musi znajdować się w partycji vendor/vendor/etc/selinux/.

Zmiany w pamięci współdzielonej w Androidzie 17

Począwszy od Androida 17, urządzenia z tymi właściwościami muszą włączyć funkcję zasad memfd_class i zaktualizować zasady dotyczące pamięci współdzielonej, aby obsługiwać obiekty klasy memfd_file:

  • Interfejs API dostawcy na poziomie 202604 lub wyższym, aby umożliwić dostawcom i producentom OEM aktualizowanie zasad dostawcy w celu obsługi memfd. Umożliwia też aktualizację istniejących urządzeń do wyższych wersji Androida bez konieczności aktualizowania partycji dostawcy.
  • android16-6.12 lub nowszy, ponieważ te jądra obsługują funkcję memfd_class, która jest wymagana do wdrożenia szczegółowych zasad dotyczących memfd.

Włączanie możliwości zasad memfd_class

Do niedawna system SELinux oznaczał memfd jako plik tego samego typu co jego system plików – tmpfs. Z punktu widzenia zasad nie można było odróżnić memfd od innego pliku na zamontowanym woluminie tmpfs. Teraz SELinux przypisuje memfd etykietę z kontekstem bezpieczeństwa procesu przydzielania, a memfds są traktowane jako obiekty klasy memfd_file. Ta funkcja jest chroniona przez możliwość memfd_class, aby zachować zgodność wsteczną ze starszymi środowiskami przestrzeni użytkownika.

Aby włączyć funkcję zasad memfd_class, utwórz plik policy_capabilities w folderze BOARD_VENDOR_SEPOLICY_DIRS. Plik powinien zawierać ten wpis:

# $BOARD_VENDOR_SEPOLICY_DIRS/*/policy_capabilities
policycap memfd_class;

Następnie ponownie skompiluj obrazy i prześlij je na urządzenie, aby sprawdzić, czy funkcja jest włączona.

Sprawdzanie, czy funkcja zasad memfd_class jest włączona

Aby sprawdzić stan funkcji zasad memfd_class, użyj tego polecenia:

adb shell 'cat /sys/fs/selinux/policy_capabilities/memfd_class'

Jeśli wynikiem jest 1, funkcja zasady memfd_class jest włączona. W przeciwnym razie nie jest ona włączona.

Przenoszenie istniejącej zasady do memfd

Niektóre procesy używały w swoich zasadach makra tmpfs_domain(), aby uzyskać dostęp do memfds i przestrzeni nazw, na przykład:

# foo.te
tmpfs_domain(foo)

Oznacza to:

# foo.te
type_transition foo tmpfs:file foo_tmpfs;
allow foo foo_tmpfs:file { read write getattr map };

i umożliwia procesowi bar dostęp do memfds procesu foo w ten sposób:

# bar.te
allow bar foo_tmpfs:file { read write getattr map };

Po włączeniu funkcji zasad memfd_class makro tmpfs_domain() nie jest już potrzebne, ponieważ zasady platformy zostały zaktualizowane, aby umożliwić każdemu procesowi tworzenie i używanie własnego memfds, jak widać tutaj:

# system/sepolicy/private/domain.te
allow domain self:memfd_file { create read write getattr map };

memfds utworzone przez proces foo mogą być dostępne dla procesu bar w ten sposób:

# bar.te
allow bar foo:memfd_file { read write getattr map };

Zasady platformy zostały zaktualizowane, aby uwzględnić dotychczasowe użycie symbolu memfd. Jednak zasady dotyczące dostawcy i urządzenia, które używają etykiet tmpfs, muszą zostać zaktualizowane, aby używać etykiet memfd_file. Jeśli zasady są wspólne dla układów SoC lub urządzeń, które nie mają interfejsu API dostawcy na poziomie 202604 lub wyższym, zalecamy zachowanie starszych zasad tmpfs wraz z nowymi zasadami memfd_file w celu zapewnienia zgodności.

Identyfikowanie odmów dostępu AVC związanych z memfd

Odmowy związane z Memfd można pobrać za pomocą tego polecenia:

adb shell logcat -d -b events | grep memfd

odmowy avc z tmpfs jako celem,

Poniższy przykład pokazuje odmowę avc, która wystąpiła w procesie, który próbował zapisać dane w memfd, do którego nie miał uprawnień do zapisu:

audit(0.0:539): avc:  denied  { write } for  comm="binder:665_1" name="memfd:MessageQueue"
dev="tmpfs" ino=8324 scontext=u:r:mediacodec:s0 tcontext=u:object_r:tmpfs:s0 tclass=file
permissive=0

Gdy funkcja zasady memfd_class jest włączona, kontekstem docelowym elementu memfd jest kontekst zabezpieczeń procesu przydzielania, a nie tmpfs, a klasą docelową jest memfd_file, a nie file. Jeśli więc widzisz avc odrzucenia związane z memfd, gdzie memfd jest oznaczony jako plik tmpfs, oznacza to, że funkcja zasad memfd_class nie jest włączona.

odmowy avc z memfd_file jako klasą docelową,

Poniższy przykład pokazuje odmowę avc, która wystąpiła w procesie próbującym zapisać dane w memfd, do którego nie miał uprawnień do zapisu. Włączona była funkcja zasad memfd_class. Dodatkowo w tym samym momencie logd wyemitował wiersz po odmowie:

audit(0.0:86): avc: denied { read } for
path=2F6D656D66643A4D6564696142756666657247726F7570202864656C6574656429 ino=512 dev=""
scontext=u:r:mediaserver:s0 tcontext=u:object_r:mediaextractor:s0 tclass=memfd_file

auditd  : Decoded path for audit(0.0:86): /memfd:MediaBufferGroup (deleted)

Pasująca sygnatura czasowa wskazuje, że Decoded path for … log jest powiązany z odmową avc z sygnaturą czasową 0.0.86. Ten log dekoduje ciąg szesnastkowy z wartości ścieżki w avc odmowie i podaje nazwę memfd regionu pamięci, co może być przydatne do zrozumienia, który bufor jest udostępniany. Kontekst źródłowy i kontekst docelowy pomagają zrozumieć, które procesy muszą współdzielić pamięć. Z powyższego przykładu jasno wynika, że proces mediaserver musi mieć dostęp do memfds procesu mediaextractor. Dlatego odpowiednie zasady to:

# mediaserver.te
allow mediaserver mediaextractor:memfd_file { getattr read write map };

Aktualizacje domeny zabezpieczeń w Androidzie 17

Interfejs ASharedMemory_create() API w Androidzie 17 implementuje logikę warunkową, która umożliwia wybór między starszym sterownikiem ashmem a platformą ASharedMemory_create() do przydzielania pamięci współdzielonej.memfd

W przypadku urządzeń spełniających memfd wymagania (poziom interfejsu API dostawcy 202604 lub wyższy i jądro android16-6.12 lub nowsze) interfejs API ocenia targetSdkVersion aplikacji wywołującej. Jeśli docelowa wersja pakietu SDK to 37 lub nowsza, przydzielana jest wartość memfd. Dzięki temu deweloperzy mogą rozwiązywać problemy, które napotykają podczas uaktualniania docelowej wersji pakietu SDK.

Jeśli urządzenie nie spełnia memfd's wymagań wstępnych, ASharedMemory przełącza się na ashmem. Zapewnia to zgodność uaktualnionych urządzeń ze starszymi partycjami dostawcy lub jądrami.

Aby wymusić to przejście, zasady SELinux platformy blokują aplikacjom kierowanym na pakiet SDK w wersji 37 lub nowszej w domenach zabezpieczeń platform_app, priv_appuntrusted_app otwieranie /dev/ashmem i wywoływanie poleceń ashmem ioctl na memfd. Osiąga się to przez podzielenie domen aplikacji na podstawie docelowej wersji pakietu SDK. Wprowadzamy domeny zabezpieczeń platform_app_36, priv_app_36untrusted_app_34, które wraz z innymi domenami aplikacji zachowują uprawnienia do otwierania ashmem i możliwość wywoływania poleceń ioctl ashmem na memfds.

W przyszłej wersji Androida zestaw aplikacji, które zachowają uprawnienia do otwierania urządzenia ashmem i wywoływania poleceń ashmem ioctl na memfds, zostanie ograniczony do platform_app_36, priv_app_36untrusted_app_34 oraz niezaufanych domen aplikacji w przypadku starszych wersji pakietu SDK.

Niestandardowe zasady SELinux dostawcy lub producenta OEM dla aplikacji, które przypinają docelową wersję pakietu SDK, muszą zostać zaktualizowane, aby były zgodne z tymi zmianami w domenach, jak opisano w kolejnych sekcjach.

Aktualizacje domeny SELinux platform_app

Domena platform_app jest dzielona na podstawie targetSdkVersion aplikacji. Aplikacje platformy kierowane na pakiet SDK w wersji 37 lub nowszej mają przypisaną domenę platform_app, a aplikacje kierowane na pakiet SDK w wersji 36 lub starszej – domenę platform_app_36. Domena platform_app_36 zachowuje możliwość otwierania /dev/ashmem ze względu na zgodność wsteczną. Aby uprościć zarządzanie zasadami w obu domenach, użyj atrybutu platform_app_all.

Rozważmy sytuację, w której aplikacja platformy sample-plat-app musi odczytywać dane z /dev/foo_device i zapisywać je w /dev/foo_device. Obecna zasada SELinux dostawcy może wyglądać tak:

# This will only allow sample-plat-app to access the device if it
# is placed in the platform_app domain (i.e. target SDK version is 37 or higher).
allow platform_app foo_device:chr_file rw_file_perms;

Jeśli jednak sample-plat-app jest przypięty do docelowego pakietu SDK w wersji 36, jest umieszczany w domenie platform_app_36, a zasady SELinux z wcześniejszej wersji nie będą stosowane. W takim przypadku wystąpi następujące odrzucenie AVC:

auditd  : type=1400 audit(0.0:11): avc:  denied  { read write } for  comm="sample-plat-app" path="/dev/foo_device" dev="tmpfs" ino=1609 scontext=u:r:platform_app_36:s0:c512,c768 tcontext=u:object_r:foo_device:s0 tclass=chr_file permissive=0

Aby to naprawić, można zaktualizować zasadę, ponieważ aplikacja powinna zawsze mieć dostęp do węzła urządzenia:

# This allows sample-plat-app to access the device independent of
# target SDK version.
allow platform_app_all foo_device:chr_file rw_file_perms;

W niektórych sytuacjach platform_app_all może nie działać. Jeśli na przykład makro hal_client_domain() jest używane z makrem platform_app_all, kompilacja zasady nie powiedzie się. Dzieje się tak, ponieważ platform_app_all jest atrybutem, a hal_client_domain() próbuje dołączyć do niego kolejny atrybut, co jest niemożliwe:

# platform_app.te
hal_client_domain(platform_app, hal_foo)

W takich przypadkach musisz użyć bezpośrednio typu platform_app_36, więc Twoje zasady będą zawierać te informacje:

# platform_app.te
hal_client_domain(platform_app, hal_foo)

# platform_app_36.te
hal_client_domain(platform_app_36, hal_foo)

Aktualizacje domeny SELinux aplikacji uprzywilejowanych

Domena priv_app jest dzielona na podstawie targetSdkVersion aplikacji. Aplikacje uprzywilejowane kierowane na pakiet SDK w wersji 37 lub nowszej mają przypisaną domenę priv_app, a aplikacje kierowane na pakiet SDK w wersji 36 lub starszej korzystają z domeny priv_app_36. Domena priv_app_36 zachowuje możliwość otwierania /dev/ashmem ze względu na zgodność wsteczną. Aby uprościć zarządzanie zasadami w obu domenach, użyj atrybutu priv_app_all.

Rozważmy sytuację, w której aplikacja platformy sample-priv-app musi odczytywać dane z /dev/foo_device i zapisywać je w /dev/foo_device. Obecna zasada SELinux dostawcy może wyglądać tak:

# This will only allow sample-priv-app to access the device if it
# is placed in the priv_app domain (i.e. target SDK version is 37 or higher).
allow priv_app foo_device:chr_file rw_file_perms;

Jeśli jednak sample-priv-app jest przypięty do docelowego pakietu SDK w wersji 36, jest umieszczany w domenie priv_app_36, a zasady SELinux z wcześniejszej wersji nie będą stosowane. W takim przypadku wystąpi następujące odrzucenie AVC:

auditd  : type=1400 audit(0.0:11): avc:  denied  { read write } for  comm="sample-priv-app" path="/dev/foo_device" dev="tmpfs" ino=1609 scontext=u:r:priv_app_36:s0:c512,c768 tcontext=u:object_r:foo_device:s0 tclass=chr_file permissive=0

Aby to naprawić, można zaktualizować zasadę, ponieważ aplikacja powinna zawsze mieć dostęp do węzła urządzenia:

# This allows sample-priv-app to access the device independent of
# target SDK version.
allow priv_app_all foo_device:chr_file rw_file_perms;

W niektórych sytuacjach priv_app_all może nie działać. Jeśli na przykład makro hal_client_domain() jest używane z makrem priv_app_all, kompilacja zasady nie powiedzie się. Dzieje się tak, ponieważ priv_app_all jest atrybutem, a hal_client_domain() próbuje dołączyć do niego kolejny atrybut, co jest niemożliwe:

# priv_app.te
hal_client_domain(priv_app, hal_foo)

W takich przypadkach musisz użyć bezpośrednio typu priv_app_36, więc pliki zasad będą wyglądać mniej więcej tak:

# priv_app.te
hal_client_domain(priv_app, hal_foo)

# priv_app_36.te
hal_client_domain(priv_app_36, hal_foo)

Aktualizacje domeny SELinux untrusted_app

Domena untrusted_app jest dzielona na podstawie targetSdkVersion aplikacji. Niezaufane aplikacje kierowane na pakiet SDK w wersji 37 lub nowszej są przypisywane do domeny untrusted_app, a aplikacje kierowane na pakiet SDK w wersji 34–36 (włącznie) są przypisywane do nowej domeny untrusted_app_34. Domena untrusted_app_34 oraz domeny untrusted_app_X, gdzie „X” to starsza wersja docelowego pakietu SDK, zachowują możliwość otwierania `/dev/ashmem` ze względu na zgodność wsteczną.