Cette page explique comment Android gère les problèmes de compatibilité des règles avec les mises à jour de la plate-forme en direct (OTA, over-the-air), où les nouveaux paramètres SELinux de la plate-forme peuvent différer des anciens paramètres SELinux du fournisseur.
Propriété et étiquetage des objets
La propriété doit être clairement définie pour chaque objet afin de séparer les règles de la plate-forme et du fournisseur. Par exemple, si les libellés de règles du fournisseur sont /dev/foo et que les libellés de règles de la plate-forme sont /dev/foo dans une OTA ultérieure, le comportement est indéfini (par exemple, un refus inattendu ou, plus grave encore, un échec du démarrage). Pour SELinux, cela se manifeste par une collision d'étiquettes. Le nœud de l'appareil ne peut comporter qu'un seul libellé, qui correspond à celui appliqué en dernier.
Par conséquent :
- Les processus qui ont besoin d'accéder au libellé qui n'a pas été appliqué perdent l'accès à la ressource.
- Les processus qui accèdent au fichier peuvent échouer, car le mauvais nœud de périphérique a été créé.
Des collisions entre les libellés de plate-forme et de fournisseur peuvent se produire pour tout objet comportant un libellé SELinux, y compris les propriétés, les services, les processus, les fichiers et les sockets. Pour éviter ces problèmes, définissez clairement la propriété de ces objets.
Espace de noms de type/attribut
En plus des conflits d'étiquettes, les noms de types et d'attributs SELinux peuvent également entrer en conflit. SELinux n'autorise pas les déclarations multiples des mêmes types et attributs. Une règle comportant des déclarations en double ne peut pas être compilée. Pour éviter les conflits de noms de types et d'attributs, il est fortement recommandé que toutes les déclarations de fournisseur commencent par le préfixe vendor_. Par exemple, les fournisseurs doivent utiliser type vendor_foo, domain; au lieu de type foo, domain;.
Propriété des fichiers
Il est difficile d'éviter les collisions pour les fichiers, car les règles de la plate-forme et du fournisseur fournissent généralement des libellés pour tous les systèmes de fichiers. Contrairement à la dénomination des types, l'utilisation d'espaces de noms pour les fichiers n'est pas pratique, car beaucoup d'entre eux sont créés par le noyau. Pour éviter ces collisions, suivez les consignes de dénomination des systèmes de fichiers de cette section. Pour Android 8.0, il s'agit de recommandations sans application technique. À l'avenir, ces recommandations seront appliquées par la Vendor Test Suite (VTS).
Système (/system)
Seule l'image système doit fournir des libellés pour les composants /system à file_contexts, service_contexts, etc. Si des libellés pour les composants /system sont ajoutés dans la règle du fournisseur, une mise à jour OTA du framework uniquement peut ne pas être possible.
Fournisseur (/vendor)
La règle SELinux de l'AOSP étiquette déjà les parties de la partition vendor avec lesquelles la plate-forme interagit, ce qui permet d'écrire des règles SELinux pour que les processus de la plate-forme puissent communiquer avec certaines parties de la partition vendor ou y accéder. Exemples :
| /vendor path | Libellé fourni par la plate-forme | Processus de la plate-forme en fonction du label |
|---|---|---|
/vendor(/.*)?
|
vendor_file
|
Tous les clients HAL du framework, ueventd, etc.
|
/vendor/framework(/.*)?
|
vendor_framework_file
|
dex2oat, appdomain, etc.
|
/vendor/app(/.*)?
|
vendor_app_file
|
dex2oat, installd, idmap, etc.
|
/vendor/overlay(/.*)
|
vendor_overlay_file
|
system_server, zygote, idmap, etc.
|
Par conséquent, des règles spécifiques doivent être respectées (appliquées via neverallows) lors de l'étiquetage de fichiers supplémentaires dans la partition vendor :
vendor_filedoit être le libellé par défaut pour tous les fichiers de la partitionvendor. La règle de la plate-forme exige cela pour accéder aux implémentations HAL de transmission.- Tous les nouveaux
exec_typesajoutés dans la partitionvendorvia le règlement du fournisseur doivent comporter l'attributvendor_file_type. Cela est appliqué par le biais de neverallows. - Pour éviter les conflits avec les futures mises à jour de la plate-forme/du framework, évitez de libeller les fichiers autres que
exec_typesdans la partitionvendor. - Toutes les dépendances de bibliothèque pour les HAL de même processus identifiés par AOSP doivent être étiquetées
same_process_hal_file..
Procfs (/proc)
Les fichiers dans /proc ne peuvent être libellés qu'avec le libellé genfscon. Dans Android 7.0, les règles platform et vendor utilisaient genfscon pour étiqueter les fichiers dans procfs.
Recommandation : Utilisez uniquement les libellés de règlement de la plate-forme /proc.
Si les processus du fournisseur doivent accéder à des fichiers dans /proc qui sont actuellement associés au libellé par défaut (proc), le règlement du fournisseur ne doit pas les libeller explicitement. Il doit plutôt utiliser le type générique proc pour ajouter des règles pour les domaines des fournisseurs. Cela permet aux mises à jour de la plate-forme de s'adapter aux futures interfaces du noyau exposées via procfs et de les étiqueter explicitement si nécessaire.
Debugfs (/sys/kernel/debug)
Debugfs peut être libellé à la fois dans file_contexts et genfscon. Dans Android 7.0 à Android 10, les libellés de plate-forme et de fournisseur sont debugfs.
Dans Android 11, il est impossible d'accéder à debugfs ni de le monter sur les appareils de production. Les fabricants d'appareils doivent supprimer debugfs.
Tracefs (/sys/kernel/debug/tracing)
Tracefs peut être libellé à la fois dans file_contexts et genfscon. Dans Android 7.0, seuls les libellés de plate-forme tracefs.
Recommandation : Seule la plate-forme peut libeller tracefs.
Sysfs (/sys)
Les fichiers de /sys peuvent être libellés à l'aide de file_contexts et de genfscon. Dans Android 7.0, la plate-forme et le fournisseur utilisent genfscon pour libeller les fichiers dans sysfs.
Recommandation : La plate-forme peut identifier les nœuds sysfs qui ne sont pas spécifiques à un appareil. Sinon, seul le fournisseur peut libeller les fichiers.
tmpfs (/dev)
Les fichiers de /dev peuvent être étiquetés dans file_contexts. Dans Android 7.0, la plate-forme et les fichiers de libellés du fournisseur sont ici.
Recommandation : Le fournisseur ne peut libeller que les fichiers dans /dev/vendor (par exemple, /dev/vendor/foo, /dev/vendor/socket/bar).
Rootfs (/)
Les fichiers de / peuvent être étiquetés dans file_contexts. Dans Android 7.0, les fichiers de libellés de plate-forme et de fournisseur se trouvent ici.
Recommandation : Seul le système peut étiqueter les fichiers dans /.
Données (/data)
Les données sont libellées à l'aide d'une combinaison de file_contexts et de seapp_contexts.
Recommandation : Interdisez l'étiquetage des fournisseurs en dehors de /data/vendor. Seule la plate-forme peut libeller d'autres parties de /data.
Version des libellés Genfs
À partir du niveau d'API du fournisseur 202504, les nouveaux libellés SELinux attribués avec genfscon dans system/sepolicy/compat/plat_sepolicy_genfs_ver.cil sont facultatifs pour les anciennes partitions vendor. Cela permet aux anciennes partitions vendor de conserver leur implémentation SEPolicy existante.
Ce paramètre est contrôlé par la variable Makefile BOARD_GENFS_LABELS_VERSION, qui est stockée dans /vendor/etc/selinux/genfs_labels_version.txt.
Exemple :
-
Dans le niveau d'API du fournisseur 202404, le nœud
/sys/class/udcest libellésysfspar défaut. -
À partir du niveau d'API du fournisseur 202504,
/sys/class/udcest libellésysfs_udc.
Toutefois, /sys/class/udc peut être utilisé par des partitions vendor utilisant le niveau d'API 202404, soit avec le libellé sysfs par défaut, soit avec un libellé spécifique au fournisseur. Le libellé inconditionnel /sys/class/udc en tant que sysfs_udc peut casser la compatibilité avec ces partitions vendor. En cochant BOARD_GENFS_LABELS_VERSION, la plate-forme continue d'utiliser les libellés et les autorisations précédents pour les anciennes partitions vendor.
BOARD_GENFS_LABELS_VERSION peut être supérieur ou égal au niveau d'API du fournisseur. Par exemple, les partitions vendor utilisant le niveau d'API 202404 peuvent définir BOARD_GENFS_LABELS_VERSION sur 202504 pour adopter les nouveaux libellés introduits dans 202504. Consultez la liste des
libellés genfs spécifiques à 202504.
Lors de l'étiquetage des nœuds genfscon, la plate-forme doit tenir compte des anciennes partitions vendor et implémenter des mécanismes de secours pour la compatibilité, si nécessaire. La plate-forme peut utiliser des bibliothèques réservées à la plate-forme pour interroger la version des libellés genfs.
-
Sur les plates-formes natives, utilisez
libgenfslabelsversion. Consultezgenfslabelsversion.hpour le fichier d'en-tête delibgenfslabelsversion. -
Sur Java, utilisez
android.os.SELinux.getGenfsLabelsVersion().
Politique publique de la plate-forme
La règle SELinux de la plate-forme est divisée en parties privées et publiques. Le règlement public de la plate-forme se compose de types et d'attributs qui sont toujours disponibles pour un niveau d'API du fournisseur, et qui servent d'API entre la plate-forme et le fournisseur. Cette règle est exposée aux rédacteurs de règles des fournisseurs pour leur permettre de créer des fichiers de règles de fournisseur qui, combinés à la règle privée de la plate-forme, aboutissent à une règle entièrement fonctionnelle pour un appareil. La règle publique de la plate-forme est définie dans system/sepolicy/public.
Par exemple, un type vendor_init, représentant le processus d'initialisation dans le contexte du fournisseur, est défini sous system/sepolicy/public/vendor_init.te :
type vendor_init, domain;
Les fournisseurs peuvent se référer au type vendor_init pour écrire des règles de conformité personnalisées :
# Allow vendor_init to set vendor_audio_prop in vendor's init scripts
set_prop(vendor_init, vendor_audio_prop)Attributs de compatibilité
La stratégie SELinux est une interaction entre les types source et cible pour des classes d'objets et des autorisations spécifiques. Chaque objet (processus, fichiers, par exemple) affecté par la règle SELinux ne peut avoir qu'un seul type, mais ce type peut avoir plusieurs attributs.
La stratégie est principalement rédigée en termes de types existants. Ici, vendor_init et debugfs sont des types :
allow vendor_init debugfs:dir { mounton };
Cela fonctionne, car la règle a été écrite en tenant compte de tous les types. Toutefois, si les règles du fournisseur et de la plate-forme utilisent des types spécifiques, et que le libellé d'un objet spécifique change dans une seule de ces règles, l'autre peut contenir une règle qui s'appuyait auparavant sur un accès accordé ou perdu. Par exemple, supposons que la règle de plate-forme libelle les nœuds sysfs comme sysfs :
/sys(/.*)? u:object_r:sysfs:s0
La règle relative aux fournisseurs accorde l'accès à /sys/usb, qui porte la mention sysfs :
allow vendor_init sysfs:chr_file rw_file_perms;
Si la règle de la plate-forme est modifiée pour que /sys/usb soit associé à sysfs_usb, la règle du fournisseur reste la même, mais vendor_init perd l'accès à /sys/usb en raison de l'absence de règle pour le nouveau type sysfs_usb :
/sys/usb u:object_r:sysfs_usb:s0
Pour résoudre ce problème, Android introduit le concept d'attributs versionnés. Au moment de la compilation, le système de compilation traduit automatiquement les types publics de plate-forme utilisés dans la règle du fournisseur en ces attributs versionnés. Cette traduction est activée par des fichiers de mappage qui associent un attribut versionné à un ou plusieurs types publics de la plate-forme.
Par exemple, supposons que /sys/usb soit associé au libellé sysfs dans la règle de plate-forme 202504, et que la règle du fournisseur 202504 accorde à vendor_init l'accès à /sys/usb. Dans ce cas :
-
La règle
allow vendor_init sysfs:chr_file rw_file_perms;est écrite par la règle du fournisseur, car/sys/usbest libellésysfsdans la règle de la plate-forme 202504. Lorsque le système de compilation compile la règle du fournisseur, il la traduit automatiquement enallow vendor_init_202504 sysfs_202504:chr_file rw_file_perms;. Les attributsvendor_init_202504etsysfs_202504correspondent aux typesvendor_initetsysfs, qui sont les types définis par la plate-forme. -
Le système de compilation génère un fichier de mappage d'identité
/system/etc/selinux/mapping/202504.cil. Étant donné que les partitionssystemetvendorutilisent la même version202504, le fichier de mappage contient des mappages d'identité detype_202504àtype. Par exemple,vendor_init_202504est mappé survendor_initetsysfs_202504sursysfs:(typeattributeset sysfs_202504 (sysfs)) (typeattributeset vendor_init_202504 (vendor_init)) ...
Lorsque la version passe de 202504 à 202604, un nouveau fichier de mappage pour les partitions 202504 vendor est créé sous system/sepolicy/private/compat/202504/202504.cil, qui est installé sur /system/etc/selinux/mapping/202504.cil pour les partitions 202604 ou ultérieures system. Initialement, ce fichier de mappage contient des mappages d'identité, comme décrit précédemment. Si un nouveau libellé sysfs_usb
pour /sys/usb est ajouté au règlement de la plate-forme 202604, le fichier de mapping est mis à jour pour mapper sysfs_202504 sur sysfs_usb :
(typeattributeset sysfs_202504 (sysfs sysfs_usb)) (typeattributeset vendor_init_202504 (vendor_init)) ...
Cette mise à jour permet à la règle allow
vendor_init_202504 sysfs_202504:chr_file rw_file_perms; convertie pour les fournisseurs d'accorder automatiquement l'accès vendor_init au nouveau type sysfs_usb.
Pour maintenir la compatibilité avec les anciennes partitions vendor, chaque fois qu'un nouveau type public est ajouté, il doit être mappé à au moins un des attributs versionnés dans le fichier de mappage system/sepolicy/private/compat/ver/ver.cil ou être listé sous system/sepolicy/private/compat/ver/ver.ignore.cil pour indiquer qu'il n'existe aucun type correspondant dans les versions précédentes du fournisseur.
La combinaison de la règle de la plate-forme, de la règle du fournisseur et du fichier de mappage permet au système de se mettre à jour sans mettre à jour la règle du fournisseur. De plus, la conversion en attributs versionnés s'effectue automatiquement. La règle du fournisseur n'a donc pas besoin de gérer la gestion des versions et peut continuer à utiliser les types publics tels quels.
Règles publiques et produit public system_ext
À partir d'Android 11, les partitions system_ext et product sont autorisées à exporter leurs types publics désignés vers la partition vendor. Comme le règlement public de la plate-forme, le règlement relatif aux fournisseurs utilise des types et des règles automatiquement traduits en attributs versionnés, par exemple de type à type_ver, où ver correspond au niveau d'API du fournisseur de la partition vendor.
Lorsque les partitions system_ext et product sont basées sur la même version de plate-forme ver, le système de compilation génère des fichiers de mappage de base vers system_ext/etc/selinux/mapping/ver.cil et product/etc/selinux/mapping/ver.cil, qui contiennent des mappages d'identité de type à type_ver.
La règle du fournisseur peut accéder à type avec l'attribut versionné type_ver.
Si seules les partitions system_ext et product sont mises à jour, par exemple de ver à ver+1 (ou ultérieurement), tandis que la partition vendor reste à ver, il est possible que la règle du fournisseur perde l'accès aux types des partitions system_ext et product. Pour éviter toute rupture, les partitions system_ext et product doivent fournir des fichiers de mappage des types concrets vers les attributs type_ver. Chaque partenaire est responsable de la maintenance des fichiers de mappage s'il prend en charge la partition ver vendor avec ver+1 (ou version ultérieure) des partitions system_ext et product.
Pour installer des fichiers de mappage dans les partitions system_ext et product, les intégrateurs ou fournisseurs d'appareils doivent :
- Copiez les fichiers de mappage de base générés à partir des partitions ver,
system_extetproductdans leur arborescence source. - Modifiez les fichiers de mappage si nécessaire.
-
Installez les fichiers de mappage sur les partitions
system_extetproductde ver+1 (ou version ultérieure).
Par exemple, supposons que la partition 202504 system_ext comporte un type public nommé foo_type. Ensuite, system_ext/etc/selinux/mapping/202504.cil dans la partition 202504 system_ext se présente comme suit :
(typeattributeset foo_type_202504 (foo_type)) (expandtypeattribute foo_type_202504 true) (typeattribute foo_type_202504)
Si bar_type est ajouté à la partition 202604 system_ext et si bar_type doit être mappé sur foo_type pour la partition 202504 vendor, 202504.cil peut être mis à jour de (typeattributeset foo_type_202504 (foo_type)) à (typeattributeset foo_type_202504 (foo_type bar_type)), puis installé sur la partition 202604 system_ext. La partition 202504 vendor peut continuer à accéder aux foo_type et bar_type de la partition 202604 system_ext.
Modifications d'attributs pour Android 9
Les appareils qui passent à Android 9 peuvent utiliser les attributs suivants, mais les appareils lancés avec Android 9 ne le doivent pas.
Attributs du contrevenant
Android 9 inclut les attributs liés au domaine suivants :
data_between_core_and_vendor_violators. Attribut pour tous les domaines qui ne respectent pas l'exigence de ne pas partager de fichiers par chemin d'accès entrevendoretcoredomains. Les processus de plate-forme et de fournisseur ne doivent pas utiliser de fichiers sur disque pour communiquer (ABI instable). Recommandation :- Le code fournisseur doit utiliser
/data/vendor. - Le système ne doit pas utiliser
/data/vendor.
- Le code fournisseur doit utiliser
- Attribut
system_executes_vendor_violators. pour tous les domaines système (saufinitetshell domains) qui ne respectent pas l'exigence de ne pas exécuter de binaires de fournisseurs. L'exécution des binaires du fournisseur présente une API instable. La plate-forme ne doit pas exécuter directement les binaires du fournisseur. Recommandation :- Ces dépendances de plate-forme sur les binaires du fournisseur doivent se trouver derrière les HAL HIDL.
OU
- Les
coredomainsqui ont besoin d'accéder aux binaires du fournisseur doivent être déplacés vers la partitionvendoret ne plus êtrecoredomain.
- Ces dépendances de plate-forme sur les binaires du fournisseur doivent se trouver derrière les HAL HIDL.
Attributs non approuvés
Les applications non approuvées qui hébergent du code arbitraire ne doivent pas avoir accès aux services HwBinder, à l'exception de ceux considérés comme suffisamment sûrs pour être accessibles depuis de telles applications (voir les services sécurisés ci-dessous). Voici les deux principales raisons :
- Les serveurs HwBinder n'effectuent pas d'authentification du client, car HIDL n'expose actuellement pas les informations UID de l'appelant. Même si HIDL exposait de telles données, de nombreux services HwBinder fonctionnent à un niveau inférieur à celui des applications (comme les HAL) ou ne doivent pas s'appuyer sur l'identité de l'application pour l'autorisation. Par conséquent, pour plus de sécurité, l'hypothèse par défaut est que chaque service HwBinder traite tous ses clients comme étant également autorisés à effectuer les opérations proposées par le service.
- Les serveurs HAL (un sous-ensemble de services HwBinder) contiennent du code avec un taux d'incidence plus élevé de problèmes de sécurité que les composants
system/coreet ont accès aux couches inférieures de la pile (jusqu'au matériel), ce qui augmente les possibilités de contourner le modèle de sécurité Android.
Services Safe
Les services sécurisés incluent :
same_process_hwservice. Ces services (par définition) s'exécutent dans le processus du client et ont donc le même accès que le domaine client dans lequel le processus s'exécute.coredomain_hwservice. Ces services ne présentent pas les risques associés à la raison n° 2.hal_configstore_ISurfaceFlingerConfigs. Ce service est spécifiquement conçu pour être utilisé par n'importe quel domaine.hal_graphics_allocator_hwservice. Ces opérations sont également proposées par le service Bindersurfaceflinger, auquel les applications sont autorisées à accéder.hal_omx_hwservice. Il s'agit d'une version HwBinder du service Bindermediacodec, auquel les applications sont autorisées à accéder.hal_codec2_hwservice. Il s'agit d'une version plus récente dehal_omx_hwservice.
Attributs utilisables
Tous les hwservices considérés comme non sécurisés possèdent l'attribut untrusted_app_visible_hwservice. Les serveurs HAL correspondants possèdent l'attribut untrusted_app_visible_halserver. Les appareils lancés avec Android 9 NE DOIVENT PAS utiliser l'attribut untrusted.
Recommandation :
- Les applications non fiables doivent plutôt communiquer avec un service système qui communique avec le HAL HIDL du fournisseur. Par exemple, les applications peuvent communiquer avec
binderservicedomain, puismediaserver(qui est unbinderservicedomain) communique à son tour avechal_graphics_allocator.OU
- Les applications qui ont besoin d'un accès direct aux HAL
vendordoivent avoir leur propre domaine sepolicy défini par le fournisseur.
Tests d'attributs de fichier
Android 9 inclut des tests au moment de la compilation qui garantissent que tous les fichiers situés à des emplacements spécifiques possèdent les attributs appropriés (par exemple, que tous les fichiers de sysfs possèdent l'attribut sysfs_type requis).
Libellés des contextes SELinux
Pour prendre en charge la distinction entre les règles sepolicy de la plate-forme et celles du fournisseur, le système crée les fichiers de contexte SELinux différemment pour les séparer.
Contextes de fichier
Android 8.0 a introduit les modifications suivantes pour file_contexts :
- Pour éviter une surcharge de compilation supplémentaire sur l'appareil au démarrage, les
file_contextsn'existent plus sous forme binaire. À la place, il s'agit de fichiers texte d'expressions régulières lisibles, tels que{property, service}_contexts(comme avant la version 7.0). - Les
file_contextssont répartis dans deux fichiers :plat_file_contexts- Plate-forme Android
file_contextsans libellés spécifiques à l'appareil, à l'exception des libellés des parties de la partition/vendorqui doivent être libellées précisément pour assurer le bon fonctionnement des fichiers sepolicy. - Doit résider dans la partition
systemà/system/etc/selinux/plat_file_contextssur l'appareil et être chargé parinitau démarrage avec lefile_contextdu fournisseur.
- Plate-forme Android
vendor_file_contextsfile_contextspécifique à l'appareil, créé en combinantfile_contextstrouvé dans les répertoires pointés parBOARD_SEPOLICY_DIRSdans les fichiersBoardconfig.mkde l'appareil.- Doit être installé à l'emplacement
/vendor/etc/selinux/vendor_file_contextsdans la partitionvendoret être chargé parinitau démarrage avec la plate-formefile_context.
Contextes de propriété
Dans Android 8.0, property_contexts est divisé en deux fichiers :
plat_property_contexts- Plate-forme Android
property_contextsans libellé spécifique à l'appareil. - Doit résider dans la partition
systemà/system/etc/selinux/plat_property_contextset être chargé parinitau début avecproperty_contextsdu fournisseur.
- Plate-forme Android
vendor_property_contextsproperty_contextspécifique à l'appareil, créé en combinantproperty_contextstrouvé dans les répertoires pointés parBOARD_SEPOLICY_DIRSdans les fichiersBoardconfig.mkde l'appareil.- Doit résider dans la partition
vendorà/vendor/etc/selinux/vendor_property_contextset être chargé parinitau démarrage avec la plate-formeproperty_context
Contextes de service
Dans Android 8.0, le fichier service_contexts est divisé entre les fichiers suivants :
plat_service_contextsservice_contextspécifique à la plate-forme Android pourservicemanager.service_contextne comporte pas de libellés spécifiques à l'appareil.- Doit résider dans la partition
systemà/system/etc/selinux/plat_service_contextset être chargé parservicemanagerau début avec le fournisseurservice_contexts.
vendor_service_contextsservice_contextspécifique à l'appareil, créé en combinantservice_contextstrouvé dans les répertoires pointés parBOARD_SEPOLICY_DIRSdans les fichiersBoardconfig.mkde l'appareil.- Doit résider dans la partition
vendorà l'adresse/vendor/etc/selinux/vendor_service_contextset être chargé parservicemanagerau démarrage avec la plate-formeservice_contexts. - Bien que
servicemanagerrecherche ce fichier au démarrage, pour un appareilTREBLEentièrement conforme, le fichiervendor_service_contextsNE DOIT PAS exister. En effet, toute interaction entre les processusvendoretsystemDOIT passer parhwservicemanager/hwbinder.
plat_hwservice_contexts- Plate-forme Android
hwservice_contextpourhwservicemanagersans libellé spécifique à l'appareil. - Doit résider dans la partition
systemà/system/etc/selinux/plat_hwservice_contextset être chargé parhwservicemanagerau début avecvendor_hwservice_contexts.
- Plate-forme Android
vendor_hwservice_contextshwservice_contextspécifique à l'appareil, créé en combinanthwservice_contextstrouvé dans les répertoires pointés parBOARD_SEPOLICY_DIRSdans les fichiersBoardconfig.mkde l'appareil.- Doit résider dans la partition
vendorà/vendor/etc/selinux/vendor_hwservice_contextset être chargé parhwservicemanagerau démarrage avecplat_service_contexts.
vndservice_contextsservice_contextspécifique à l'appareil pourvndservicemanagercréé en combinantvndservice_contextstrouvé dans les répertoires pointés parBOARD_SEPOLICY_DIRSdansBoardconfig.mkde l'appareil.- Ce fichier doit résider dans la partition
vendorà l'adresse/vendor/etc/selinux/vndservice_contextset être chargé parvndservicemanagerau démarrage.
Contextes Seapp
Dans Android 8.0, seapp_contexts est divisé en deux fichiers :
plat_seapp_contexts- Plate-forme Android
seapp_contextsans modifications spécifiques à l'appareil. - Doit résider dans la partition
systemà l'adresse/system/etc/selinux/plat_seapp_contexts.
- Plate-forme Android
vendor_seapp_contexts- Extension spécifique à l'appareil de la plate-forme
seapp_contextcréée en combinantseapp_contextstrouvés dans les répertoires pointés parBOARD_SEPOLICY_DIRSdans les fichiersBoardconfig.mkde l'appareil. - Doit résider dans la partition
vendorà l'adresse/vendor/etc/selinux/vendor_seapp_contexts.
- Extension spécifique à l'appareil de la plate-forme
Autorisations MAC
Dans Android 8.0, mac_permissions.xml est divisé en deux fichiers :
- Plate-forme
mac_permissions.xml- Plate-forme Android
mac_permissions.xmlsans modifications spécifiques à l'appareil. - Doit résider dans la partition
systemà l'adresse/system/etc/selinux/.
- Plate-forme Android
- Hors plate-forme
mac_permissions.xml- Extension spécifique à l'appareil de la plate-forme
mac_permissions.xmlcréée à partir demac_permissions.xmltrouvée dans les répertoires pointés parBOARD_SEPOLICY_DIRSdans les fichiersBoardconfig.mkde l'appareil. - Doit résider dans la partition
vendorà l'adresse/vendor/etc/selinux/.
- Extension spécifique à l'appareil de la plate-forme
Modifications de la mémoire partagée pour Android 17
À partir d'Android 17, les appareils lancés avec les propriétés suivantes doivent activer la fonctionnalité de règle memfd_class et mettre à jour leur règle liée à la mémoire partagée pour prendre en charge les objets de classe memfd_file :
- Niveau d'API du fournisseur 202604 ou version ultérieure pour permettre aux fournisseurs et aux OEM de mettre à jour leur règlement relatif aux fournisseurs afin de prendre en charge
memfd. Il permet également aux appareils existants de passer à des versions supérieures d'Android sans nécessiter de mise à jour de leur partition fournisseur. - un kernel
android16-6.12ou version ultérieure, car ces kernels sont compatibles avec la fonctionnalitémemfd_class, qui est requise pour implémenter une règle précise pourmemfd.
Activer la fonctionnalité de règle memfd_class
Jusqu'à récemment, SELinux attribuait à un memfd le même type de fichier que son système de fichiers sous-jacent, à savoir tmpfs. Il était donc impossible de distinguer un memfd d'un autre fichier sur un montage tmpfs du point de vue des règles. Désormais, SELinux attribue un libellé memfd avec le contexte de sécurité du processus d'allocation, et les memfds sont traités comme des objets de classe memfd_file. Cette fonctionnalité est protégée par la fonctionnalité de règle memfd_class pour préserver la rétrocompatibilité avec les anciens environnements d'espace utilisateur.
Pour activer la fonctionnalité de règle memfd_class, créez un fichier policy_capabilities sous BOARD_VENDOR_SEPOLICY_DIRS. Le fichier doit contenir l'entrée suivante :
# $BOARD_VENDOR_SEPOLICY_DIRS/*/policy_capabilities
policycap memfd_class;Ensuite, reconstruisez vos images et flashez-les sur votre appareil pour vérifier que la fonctionnalité est activée.
Vérifier que la fonctionnalité de règle memfd_class est activée
Exécutez la commande suivante pour vérifier l'état de la fonctionnalité de règle memfd_class :
adb shell 'cat /sys/fs/selinux/policy_capabilities/memfd_class'
Si le résultat est 1, la fonctionnalité de règle memfd_class est activée. Sinon, il n'est pas activé.
Faire passer la stratégie existante à memfd
Certains processus utilisaient la macro tmpfs_domain() dans leur règle pour accéder à leur memfds et l'inclure dans un espace de noms, par exemple :
# foo.te
tmpfs_domain(foo)Cela signifie :
# foo.te type_transition foo tmpfs:file foo_tmpfs; allow foo foo_tmpfs:file { read write getattr map };
et permet au processus d'accès bar d'accéder à foo de la manière suivante :memfds
# bar.te allow bar foo_tmpfs:file { read write getattr map };
Lorsque la fonctionnalité de règle memfd_class est activée, la macro tmpfs_domain() n'est plus nécessaire, car la règle de plate-forme a été mise à jour pour permettre à n'importe quel processus de créer et d'utiliser son propre memfds, comme indiqué ici :
# system/sepolicy/private/domain.te allow domain self:memfd_file { create read write getattr map };
et memfds créé par le processus foo est accessible par le processus bar comme suit :
# bar.te allow bar foo:memfd_file { read write getattr map };
Le règlement de la plate-forme a été mis à jour pour tenir compte des utilisations existantes de memfd. Toutefois, les règles spécifiques aux fournisseurs et aux appareils qui utilisent des libellés tmpfs doivent être mises à jour pour utiliser memfd_file. Si la règle est partagée entre des SoC ou des appareils qui n'ont pas le niveau d'API fournisseur 202604 ou supérieur, il est recommandé de conserver l'ancienne règle tmpfs en plus de la nouvelle règle memfd_file pour assurer la compatibilité.
Identifier les refus d'accès AVC liés à memfd
Vous pouvez récupérer les refus liés à Memfd à l'aide de la commande suivante :
adb shell logcat -d -b events | grep memfd
Refus avc avec tmpfs comme cible
L'exemple suivant montre un refus avc rencontré par un processus qui a tenté d'écrire dans un memfd pour lequel il n'avait pas l'autorisation d'écriture :
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
Lorsque la fonctionnalité de règle memfd_class est activée, le contexte cible d'un memfd est le contexte de sécurité du processus d'allocation, et non tmpfs. La classe cible est memfd_file, et non file. Par conséquent, si vous constatez des refus avc liés à memfd, où le memfd en question est identifié comme un fichier tmpfs, la fonctionnalité de règle memfd_class n'est pas activée.
Refus AVC avec memfd_file comme classe cible
L'exemple suivant montre un refus avc rencontré par un processus qui tente d'écrire dans un memfd pour lequel il n'avait pas l'autorisation d'écrire. La fonctionnalité de règle memfd_class était activée, ainsi qu'une ligne supplémentaire émise par logd après le refus avec le même code temporel :
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)
L'horodatage correspondant indique que le Decoded path for … log est lié au refus avc avec l'horodatage 0.0.86. Ce journal décode la chaîne hexadécimale de la valeur du chemin d'accès dans le refus avc et fournit le nom de la région de mémoire memfd, ce qui peut être utile pour comprendre quel tampon est partagé. Les contextes source et cible sont utiles pour comprendre quels processus doivent partager de la mémoire. L'exemple précédent montre clairement que le processus mediaserver doit pouvoir accéder à memfds de mediaextractor. Par conséquent, la règle appropriée est la suivante :
# mediaserver.te allow mediaserver mediaextractor:memfd_file { getattr read write map };
Mises à jour du domaine de sécurité dans Android 17
L'API ASharedMemory_create() d'Android 17 implémente une logique conditionnelle pour choisir entre l'ancien pilote ashmem et le framework memfd pour les allocations de mémoire partagée.
Pour les appareils répondant aux exigences memfd (niveau d'API du fournisseur 202604 ou supérieur et noyau android16-6.12 ou version ultérieure), l'API évalue le targetSdkVersion de l'application appelante. Si la version du SDK cible est 37 ou ultérieure, un memfd est alloué. Cela permet aux développeurs de résoudre les problèmes qu'ils rencontrent lorsqu'ils mettent à niveau leur version cible du SDK.
Si l'appareil ne répond pas aux prérequis de memfd's, ASharedMemory revient à ashmem. Cela permet de maintenir la compatibilité des appareils mis à niveau avec les anciennes partitions ou les anciens noyaux du fournisseur.
Pour appliquer cette transition, la stratégie SELinux de la plate-forme empêche les applications ciblant la version 37 du SDK ou une version ultérieure dans les domaines de sécurité platform_app, priv_app et untrusted_app d'ouvrir /dev/ashmem et d'appeler des commandes ioctl ashmem sur memfd. Pour ce faire, nous divisons ces domaines d'application en fonction de la version du SDK cible. Cela introduit les domaines de sécurité platform_app_36, priv_app_36 et untrusted_app_34, qui, avec d'autres domaines d'application, conservent les autorisations d'ouverture ashmem et la possibilité d'appeler des commandes ioctl ashmem sur memfds.
Dans une future version d'Android, l'ensemble des applications qui conservent les autorisations d'ouvrir le périphérique ashmem et d'appeler les commandes ioctl ashmem sur memfds sera réduit à platform_app_36, priv_app_36 et untrusted_app_34, ainsi qu'aux domaines d'applications non fiables pour les anciennes versions du SDK.
Les règles SELinux personnalisées des fournisseurs ou des OEM pour les applications qui épinglent leur version SDK cible doivent être mises à jour pour s'aligner sur ces modifications de domaine, comme indiqué dans les sections suivantes.
Mises à jour du domaine SELinux de platform_app
Le domaine platform_app est divisé en fonction de l'targetSdkVersion de l'application. Les applications de plate-forme ciblant la version 37 du SDK ou une version ultérieure sont attribuées au domaine platform_app, tandis que celles ciblant la version 36 du SDK ou une version antérieure utilisent platform_app_36. Le domaine platform_app_36 conserve la possibilité d'ouvrir /dev/ashmem pour assurer la rétrocompatibilité. Pour simplifier la gestion des règles dans les deux domaines, utilisez l'attribut platform_app_all.
Prenons l'exemple où l'application de plate-forme sample-plat-app doit lire et écrire depuis et vers /dev/foo_device. La stratégie SELinux du fournisseur existant peut se présenter comme suit :
# 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;
Toutefois, si sample-plat-app est épinglé à la version 36 du SDK cible, il est placé dans le domaine platform_app_36. La règle SELinux précédente ne s'applique pas et le refus AVC suivant est observé :
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
Pour résoudre ce problème, la règle peut être mise à jour comme suit, car l'application doit toujours avoir accès au nœud de l'appareil :
# 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;
Il peut arriver que platform_app_all ne fonctionne pas. Par exemple, si la macro hal_client_domain() est utilisée avec platform_app_all, la compilation de la règle échoue. En effet, platform_app_all est un attribut, et hal_client_domain() tenterait d'y associer un autre attribut, ce qui n'est pas possible :
# platform_app.te
hal_client_domain(platform_app, hal_foo)
Dans ce cas, vous devez utiliser directement le type platform_app_36. Votre stratégie doit donc contenir les éléments suivants :
# platform_app.te hal_client_domain(platform_app, hal_foo) # platform_app_36.te hal_client_domain(platform_app_36, hal_foo)
Mises à jour du domaine SELinux priv_app
Le domaine priv_app est divisé en fonction de l'targetSdkVersion de l'application. Les applications privilégiées ciblant le SDK version 37 ou ultérieure sont attribuées au domaine priv_app, tandis que celles ciblant le SDK version 36 ou antérieure utilisent priv_app_36. Le domaine priv_app_36 conserve la possibilité d'ouvrir /dev/ashmem pour assurer la rétrocompatibilité. Pour simplifier la gestion des règles dans les deux domaines, utilisez l'attribut priv_app_all.
Prenons l'exemple où l'application de plate-forme sample-priv-app doit lire et écrire depuis et vers /dev/foo_device. La stratégie SELinux du fournisseur existant peut se présenter comme suit :
# 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;
Toutefois, si sample-priv-app est épinglé à la version 36 du SDK cible, il est placé dans le domaine priv_app_36. La règle SELinux précédente ne s'applique pas et le refus AVC suivant est observé :
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
Pour résoudre ce problème, la règle peut être mise à jour comme suit, car l'application doit toujours avoir accès au nœud de l'appareil :
# 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;
Il peut arriver que priv_app_all ne fonctionne pas. Par exemple, si la macro hal_client_domain() est utilisée avec priv_app_all, la compilation de la règle échouera. En effet, priv_app_all est un attribut, et hal_client_domain() tenterait d'y associer un autre attribut, ce qui n'est pas possible :
# priv_app.te
hal_client_domain(priv_app, hal_foo)
Dans ce cas, vous devez utiliser directement le type priv_app_36. Vos fichiers de règles se présenteront comme suit :
# priv_app.te hal_client_domain(priv_app, hal_foo) # priv_app_36.te hal_client_domain(priv_app_36, hal_foo)
Mises à jour du domaine SELinux untrusted_app
Le domaine untrusted_app est divisé en fonction de l'targetSdkVersion de l'application. Les applications non approuvées ciblant la version 37 du SDK ou une version ultérieure sont attribuées au domaine untrusted_app, tandis que celles ciblant les versions 34 à 36 incluses du SDK sont attribuées au nouveau domaine untrusted_app_34. Le domaine untrusted_app_34, ainsi que les domaines untrusted_app_X, où "X" est une ancienne version du SDK cible, conservent la possibilité d'ouvrir `/dev/ashmem` pour la rétrocompatibilité.