Cet article explique comment Android gère les problèmes de compatibilité des règles avec les mises à jour OTA de la plate-forme, où les nouveaux paramètres SELinux de la plate-forme peuvent différer des anciens paramètres SELinux du fournisseur.
La conception des règles SELinux basée sur Treble considère une distinction binaire entre les règles de la plate-forme et celles du fournisseur. Le schéma devient plus complexe si les partitions du fournisseur génèrent des dépendances, telles que platform
< vendor
< oem
.
Sous Android 8.0 et versions ultérieures, la règle globale SELinux est divisée en composants privés et publics. Les composants publics se composent de la stratégie et de l'infrastructure associée, qui sont garantis d'être disponibles pour une version de plate-forme. Cette règle sera exposée aux auteurs de règles de fournisseur pour permettre aux fournisseurs de créer un fichier de règles de fournisseur, qui, combiné à la règle fournie par la plate-forme, génère une règle entièrement fonctionnelle pour un appareil.
- Pour la gestion des versions, la règle de plate-forme publique exportée sera écrite sous forme d'attributs.
- Pour faciliter la rédaction des règles, les types exportés seront transformés en attributs avec version lors du processus de création de règles. Les types publics peuvent également être utilisés directement dans les décisions d'étiquetage fournies par les fichiers de contextes du fournisseur.
Android gère un mappage entre les types concrets exportés dans la stratégie de plate-forme et les attributs versionnés correspondants pour chaque version de plate-forme. Cela garantit que lorsque des objets sont associés à un type, cela ne perturbe pas le comportement garanti par le règlement public de la plate-forme dans une version précédente. Ce mappage est maintenu en conservant un fichier de mappage à jour pour chaque version de la plate-forme, qui conserve les informations d'appartenance aux attributs pour chaque type exporté dans la stratégie publique.
Propriété et étiquetage des objets
Lorsque vous personnalisez une règle dans Android 8.0 ou version ultérieure, 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 le fournisseur attribue le libellé /dev/foo
et que la plate-forme attribue ensuite le libellé /dev/foo
dans une mise à jour OTA ultérieure, le comportement sera indéfini. Pour SELinux, cela se manifeste par une collision de libellés. Le nœud de l'appareil ne peut avoir qu'un seul libellé, qui correspond à celui qui est appliqué en dernier. Par conséquent :
- Les processus qui nécessitent l'accès à la balise appliquée sans succès perdront l'accès à la ressource.
- Les processus qui obtiennent l'accès au fichier peuvent se bloquer, car le mauvais nœud d'appareil a été créé.
Les propriétés système peuvent également entraîner des collisions de noms pouvant entraîner un comportement indéfini sur le système (ainsi que pour le libellé SELinux). Des collisions entre les libellés de la plate-forme et du fournisseur peuvent se produire pour tout objet doté d'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.
En plus des collisions de libellés, les noms de type/d'attribut SELinux peuvent également entrer en conflit. Un conflit de nom de type/d'attribut entraîne toujours une erreur de compilation de la règle.
Espace de noms de type/d'attribut
SELinux n'autorise pas plusieurs déclarations du même type/attribut. La compilation d'une règle contenant des déclarations en double échouera. Pour éviter les collisions de types et de noms d'attributs, toutes les déclarations de fournisseurs doivent être associées à un espace de noms commençant par vendor_
.
type foo, domain; → type vendor_foo, domain;
Propriétés système et propriété du libellé de processus
Le meilleur moyen d'éviter les conflits de libellés est d'utiliser des espaces de noms de propriétés. Pour identifier facilement les propriétés de plate-forme et éviter les conflits de noms lors du renommage ou de l'ajout de propriétés de plate-forme exportées, assurez-vous que toutes les propriétés du fournisseur ont leurs propres préfixes:
Type de propriété | Préfixes acceptés |
---|---|
propriétés de contrôle | ctl.vendor. ctl.start$vendor. ctl.stop$vendor. init.svc.vendor.
|
lecture-écriture | vendor. |
lecture seule | ro.vendor. ro.boot. ro.hardware.
|
persistant | persist.vendor. |
Les fournisseurs peuvent continuer à utiliser ro.boot.*
(qui provient de la cmdline du kernel) et ro.hardware.*
(une propriété liée au matériel évidente).
Tous les services du fournisseur dans les fichiers de script d'initialisation doivent avoir vendor.
pour les services dans les fichiers de script d'initialisation des partitions non système. Des règles similaires sont appliquées aux libellés SELinux pour les propriétés du fournisseur (vendor_
pour les propriétés du fournisseur).
Propriété des fichiers
Il est difficile d'éviter les collisions de 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 de type, l'espace de noms des fichiers n'est pas pratique, car beaucoup d'entre eux sont créés par le noyau. Pour éviter ces collisions, suivez les consignes d'attribution de noms pour les systèmes de fichiers dans cette section. Pour Android 8.0, il s'agit de recommandations sans application technique. À l'avenir, ces recommandations seront appliquées par la suite de test de fournisseur (VTS).
Système (/system)
Seule l'image système doit fournir des libellés pour les composants /system
via file_contexts
, service_contexts
, etc. Si des libellés pour les composants /system
sont ajoutés dans la stratégie /vendor
, une mise à jour OTA réservée au framework peut ne pas être possible.
Fournisseur (/vendor)
La stratégie SELinux AOSP étiquette déjà des 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 et/ou accéder à des parties de la partition vendor
. Exemples :
chemin d'accès /vendor |
Libellé fourni par la plate-forme | Processus de la plate-forme en fonction du libellé |
---|---|---|
/vendor(/.*)?
|
vendor_file
|
Tous les clients HAL dans le 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_file
doit être le libellé par défaut de tous les fichiers de la partitionvendor
. La règle de la plate-forme nécessite cela pour accéder aux implémentations HAL de passthrough.- Tous les nouveaux
exec_types
ajoutés dans la partitionvendor
via le SEPolicy du fournisseur doivent avoir l'attributvendor_file_type
. Cela est appliqué via neverallows. - Pour éviter les conflits avec les futures mises à jour de la plate-forme/du framework, évitez d'étiqueter des fichiers autres que
exec_types
dans la partitionvendor
. - Toutes les dépendances de bibliothèque pour les HAL du même processus identifiées par AOSP doivent être libellées comme
same_process_hal_file.
.
Procfs (/proc)
Les fichiers dans /proc
ne peuvent être libellés qu'à l'aide du libellé genfscon
. Dans Android 7.0, la plate-forme et la stratégie du fournisseur utilisaient genfscon
pour ajouter des libellés aux fichiers dans procfs
.
Recommandation:Utilisez uniquement les libellés de règles de plate-forme /proc
.
Si les processus vendor
ont besoin d'accéder aux fichiers de /proc
actuellement libellés avec le libellé par défaut (proc
), la stratégie du fournisseur ne doit pas les libeller explicitement, mais utiliser le type proc
générique pour ajouter des règles pour les domaines du fournisseur. Cela permet aux mises à jour de la plate-forme d'accueillir les futures interfaces de noyau exposées via procfs
et de les étiqueter explicitement si nécessaire.
Debugfs (/sys/kernel/debug)
Debugfs
peut être libellé dans file_contexts
et genfscon
. Dans Android 7.0 à Android 10, la plate-forme et le fournisseur utilisent le libellé debugfs
.
Sous Android 11, debugfs
ne peut pas être accessible ni installé sur les appareils de production. Les fabricants d'appareils doivent supprimer debugfs
.
Tracefs (/sys/kernel/debug/tracing)
Tracefs
peut être libellé dans file_contexts
et genfscon
. Dans Android 7.0, seuls les libellés de plate-forme sont tracefs
.
Recommandation:Seule la plate-forme peut ajouter un libellé à tracefs
.
Sysfs (/sys)
Les fichiers dans /sys
peuvent être libellés à l'aide de file_contexts
et de genfscon
. Sous Android 7.0, la plate-forme et le fournisseur utilisent genfscon
pour libeller les fichiers dans sysfs
.
Recommandation:La plate-forme peut ajouter un libellé aux nœuds sysfs
qui ne sont pas spécifiques à l'appareil. Sinon, seul le fournisseur peut ajouter des libellés aux fichiers.
tmpfs (/dev)
Les fichiers de /dev
peuvent être libellés dans file_contexts
. Sous Android 7.0, les fichiers de libellés de plate-forme et de fournisseur se trouvent ici.
Recommandation:Le fournisseur ne peut étiqueter que les fichiers dans /dev/vendor
(par exemple, /dev/vendor/foo
, /dev/vendor/socket/bar
).
Rootfs (/)
Les fichiers de /
peuvent être libellé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 ajouter des libellés aux fichiers dans /
.
Données (/data)
Les données sont libellées à l'aide d'une combinaison de file_contexts
et seapp_contexts
.
Recommandation:Interdisez l'étiquetage du fournisseur en dehors de /data/vendor
. Seule la plate-forme peut ajouter des libellés à d'autres parties de /data
.
Version des libellés Genfs
À partir du niveau d'API du fournisseur 202504, les libellés SELinux plus récents attribués avec genfscon
dans system/sepolicy/compat/plat_sepolicy_genfs_{ver}.cil
sont facultatifs pour les anciennes partitions du fournisseur. Cela permet aux anciennes partitions de fournisseurs de conserver leur implémentation SEPolicy existante. Cela est contrôlé par la variable Makefile BOARD_GENFS_LABELS_VERSION
, qui est stockée dans /vendor/etc/selinux/genfs_labels_version.txt
.
Exemple :
-
Au niveau d'API du fournisseur 202404, le nœud
/sys/class/udc
est libellésysfs
par défaut. -
À partir du niveau d'API du fournisseur 202504,
/sys/class/udc
est associé à l'étiquettesysfs_udc
.
Toutefois, /sys/class/udc
peut être utilisé par les partitions du fournisseur utilisant le niveau d'API 202404, avec le libellé sysfs
par défaut ou un libellé spécifique au fournisseur. L'étiquetage inconditionnel de /sys/class/udc
en tant que sysfs_udc
pourrait endommager la compatibilité avec ces partitions de fournisseurs. En vérifiant BOARD_GENFS_LABELS_VERSION
, la plate-forme continue d'utiliser les étiquettes et les autorisations précédentes pour les anciennes partitions du fournisseur.
BOARD_GENFS_LABELS_VERSION
peut être supérieur ou égal au niveau de l'API du fournisseur. Par exemple, les partitions du fournisseur utilisant le niveau d'API 202404 peuvent définir BOARD_GENFS_LABELS_VERSION
sur 202504 pour adopter les nouveaux libellés introduits en 202504. Consultez la liste des
libellés genfs spécifiques à la version 202504.
Lors du libellé des nœuds genfscon
, la plate-forme doit prendre en compte les anciennes partitions de fournisseurs et implémenter des mécanismes de remplacement 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.
-
Pour les applications natives, utilisez
libgenfslabelsversion
. Consultezgenfslabelsversion.h
pour le fichier d'en-tête delibgenfslabelsversion
. -
Sous Java, utilisez
android.os.SELinux.getGenfsLabelsVersion()
.
Attributs de compatibilité
La stratégie SELinux est une interaction entre les types source et cible pour des classes et des autorisations d'objets spécifiques. Chaque objet (processus, fichiers, etc.) 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 écrite en termes de types existants:
allow source_type target_type:target_class permission(s);
Cela fonctionne, car la stratégie a été écrite en tenant compte de tous les types. Toutefois, si la stratégie du fournisseur et la stratégie de la plate-forme utilisent des types spécifiques, et que le libellé d'un objet spécifique ne change que dans l'une de ces stratégies, l'autre peut contenir une stratégie qui a gagné ou perdu l'accès précédemment utilisé. Exemple :
File_contexts: /sys/A u:object_r:sysfs:s0 Platform: allow p_domain sysfs:class perm; Vendor: allow v_domain sysfs:class perm;
Peut être remplacé par:
File_contexts: /sys/A u:object_r:sysfs_A:s0
Bien que la stratégie du fournisseur reste la même, v_domain
perd l'accès en raison de l'absence de stratégie pour le nouveau type sysfs_A
.
En définissant une stratégie en termes d'attributs, nous pouvons attribuer à l'objet sous-jacent un type qui comporte un attribut correspondant à la stratégie à la fois pour la plate-forme et le code du fournisseur. Vous pouvez le faire pour tous les types afin de créer efficacement une règle d'attribut dans laquelle les types concrets ne sont jamais utilisés. En pratique, cela n'est requis que pour les parties des règles qui se chevauchent entre la plate-forme et le fournisseur, qui sont définies et fournies en tant que Règles publiques de la plate-forme qui sont créées dans le cadre des règles du fournisseur.
Définir les règles publiques en tant qu'attributs avec version répond à deux objectifs de compatibilité des règles:
- Vérifiez que le code du fournisseur continue de fonctionner après la mise à jour de la plate-forme. Cela se fait en ajoutant des attributs à des types concrets pour les objets correspondant à ceux sur lesquels le code du fournisseur s'appuyait, tout en préservant l'accès.
- Possibilité de supprimer une règle. Pour ce faire, délimitez clairement les ensembles de règles en attributs pouvant être supprimés dès que la version à laquelle ils correspondent n'est plus prise en charge. Le développement peut se poursuivre sur la plate-forme, sachant que l'ancienne règle est toujours présente dans la règle du fournisseur et qu'elle sera automatiquement supprimée lors de la mise à niveau.
Écriture des règles
Pour atteindre l'objectif de ne pas avoir besoin de connaître les modifications de version spécifiques pour le développement de règles, Android 8.0 inclut un mappage entre les types de règles publiques de la plate-forme et leurs attributs. Le type foo
est mappé sur l'attribut foo_vN
, où N
est la version ciblée. vN
correspond à la variable de compilation PLATFORM_SEPOLICY_VERSION
et se présente sous la forme MM.NN
, où MM
correspond au numéro de SDK de la plate-forme et NN
est une version spécifique à la plate-forme sepolicy.
Les attributs des règles publiques ne sont pas versionnés, mais existent en tant qu'API sur laquelle la plate-forme et la stratégie du fournisseur peuvent être créées pour maintenir l'interface entre les deux partitions stable. Les rédacteurs de règles de plate-forme et de fournisseurs peuvent continuer à rédiger des règles comme elles le font aujourd'hui.
La règle publique de la plate-forme exportée en tant que allow source_foo target_bar:class
perm;
est incluse dans la règle du fournisseur. Lors de la compilation (qui inclut la version correspondante), elle est transformée en règle qui sera transmise à la partie du fournisseur de l'appareil (affichée dans le langage intermédiaire commun (CIL) transformé):
(allow source_foo_vN target_bar_vN (class (perm)))
Étant donné que les règles du fournisseur ne sont jamais en avance sur la plate-forme, elles ne doivent pas concerner les versions précédentes. Toutefois, la stratégie de la plate-forme doit savoir jusqu'où remonte la stratégie du fournisseur, inclure des attributs à ses types et définir la stratégie correspondant aux attributs versionnés.
Différences entre les règles
La création automatique d'attributs en ajoutant _vN
à la fin de chaque type ne sert à rien sans mappage des attributs sur les types dans les différences de version. Android gère un mappage entre les versions des attributs et un mappage des types sur ces attributs. Cela se fait dans les fichiers de mappage susmentionnés avec des instructions telles que (CIL):
(typeattributeset foo_vN (foo))
Mises à niveau de la plate-forme
La section suivante décrit les scénarios de mise à niveau de la plate-forme.
Mêmes types
Ce scénario se produit lorsqu'un objet ne modifie pas les libellés dans les versions de règles.
Il en va de même pour les types de source et de cible, et cela se voit avec /dev/binder
, qui est libellé binder_device
dans toutes les versions. Il est représenté dans la stratégie transformée comme suit:
binder_device_v1 … binder_device_vN
Lors de la mise à niveau de v1
vers v2
, le règlement de la plate-forme doit contenir les éléments suivants:
type binder_device; -> (type binder_device) (in CIL)
Dans le fichier de mappage v1 (CIL):
(typeattributeset binder_device_v1 (binder_device))
Dans le fichier de mappage v2 (CIL):
(typeattributeset binder_device_v2 (binder_device))
Dans le règlement sur les fournisseurs (CIL) de la version 1 :
(typeattribute binder_device_v1) (allow binder_device_v1 …)
Dans le règlement sur les fournisseurs (CIL) v2 :
(typeattribute binder_device_v2) (allow binder_device_v2 …)
Nouveaux types
Ce scénario se produit lorsque la plate-forme a ajouté un nouveau type, ce qui peut se produire lors de l'ajout de nouvelles fonctionnalités ou lors du renforcement des règles.
- Nouvelle fonctionnalité Lorsque le type étiquette un objet qui n'existait pas auparavant (tel qu'un nouveau processus de service), le code du fournisseur n'interagissait pas directement avec lui auparavant. Par conséquent, aucune stratégie correspondante n'existe. Le nouvel attribut correspondant au type n'a pas d'attribut dans la version précédente et n'a donc pas besoin d'une entrée dans le fichier de mappage ciblant cette version.
- Renforcement des règles Lorsque le type représente un renforcement des règles, l'attribut de nouveau type doit renvoyer à une chaîne d'attributs correspondant à la précédente (comme dans l'exemple précédent, où
/sys/A
est remplacé desysfs
parsysfs_A
). Le code du fournisseur s'appuie sur une règle permettant d'accéder àsysfs
et doit inclure cette règle en tant qu'attribut du nouveau type.
Lors de la mise à niveau de v1
vers v2
, le règlement de la plate-forme doit contenir les éléments suivants:
type sysfs_A; -> (type sysfs_A) (in CIL) type sysfs; (type sysfs) (in CIL)
Dans le fichier de mappage v1 (CIL):
(typeattributeset sysfs_v1 (sysfs sysfs_A))
Dans le fichier de mappage v2 (CIL):
(typeattributeset sysfs_v2 (sysfs)) (typeattributeset sysfs_A_v2 (sysfs_A))
Dans le règlement sur les fournisseurs (CIL) de la version 1 :
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
Dans le règlement sur les fournisseurs (CIL) v2 :
(typeattribute sysfs_A_v2) (allow … sysfs_A_v2 …) (typeattribute sysfs_v2) (allow … sysfs_v2 …)
Types supprimés
Ce scénario (rare) se produit lorsqu'un type est supprimé, ce qui peut se produire lorsque l'objet sous-jacent:
- Il reste, mais reçoit un libellé différent.
- est supprimé par la plate-forme ;
Lors de l'assouplissement des règles, un type est supprimé et l'objet associé à ce type reçoit un autre libellé déjà existant. Il s'agit d'une fusion des mappages d'attributs: le code du fournisseur doit toujours pouvoir accéder à l'objet sous-jacent par l'attribut qu'il possédait auparavant, mais le reste du système doit désormais pouvoir y accéder avec son nouvel attribut.
Si l'attribut auquel il a été attribué est nouveau, le changement de libellé est identique à celui du nouveau type, sauf que lorsqu'un libellé existant est utilisé, l'ajout du nouvel attribut de l'ancien type entraînerait l'accès à d'autres objets également libellés avec ce type. C'est essentiellement ce que fait la plate-forme, et c'est considéré comme un compromis acceptable pour maintenir la compatibilité.
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
Exemple de version 1: Réduction des types (suppression de sysfs_A)
Lors de la mise à niveau de v1
vers v2
, le règlement de la plate-forme doit contenir les éléments suivants:
type sysfs; (type sysfs) (in CIL)
Dans le fichier de mappage 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))
Dans le fichier de mappage v2 (CIL):
(typeattributeset sysfs_v2 (sysfs))
Dans le règlement sur les fournisseurs (CIL) de la version 1 :
(typeattribute sysfs_A_v1) (allow … sysfs_A_v1 …) (typeattribute sysfs_v1) (allow … sysfs_v1 …)
Dans le règlement sur les fournisseurs (CIL) v2 :
(typeattribute sysfs_v2) (allow … sysfs_v2 …)
Exemple de version 2: Suppression complète (type foo)
Lors de la mise à niveau de v1
vers v2
, le règlement de la plate-forme doit contenir les éléments suivants:
# nothing - we got rid of the type
Dans le fichier de mappage v1 (CIL):
(type foo) #needed in case vendors used the foo label on objects (typeattributeset foo_v1 (foo))
Dans le fichier de mappage v2 (CIL):
# nothing - get rid of it
Dans le règlement sur les fournisseurs (CIL) de la version 1 :
(typeattribute foo_v1) (allow foo …) (typeattribute sysfs_v1) (allow sysfs_v1 …)
Dans le règlement sur les fournisseurs (CIL) v2 :
(typeattribute sysfs_v2) (allow sysfs_v2 …)
Nouveau cours/nouvelles autorisations
Ce scénario se produit lorsqu'une mise à niveau de la plate-forme introduit de nouveaux composants de stratégie qui n'existent pas dans les versions précédentes. Par exemple, lorsque Android a ajouté le gestionnaire d'objets servicemanager
qui a créé les autorisations d'ajout, de recherche et de liste, les démons du fournisseur souhaitant s'enregistrer auprès de servicemanager
avaient besoin d'autorisations qui n'étaient pas disponibles. Sous Android 8.0, seule la stratégie de la plate-forme peut ajouter de nouvelles classes et autorisations.
Pour autoriser tous les domaines qui auraient pu être créés ou étendus par la stratégie du fournisseur à utiliser la nouvelle classe sans entrave, la stratégie de la plate-forme doit inclure une règle semblable à la suivante:
allow {domain -coredomain} *:new_class perm;
Il peut même être nécessaire de définir une règle autorisant l'accès pour tous les types d'interfaces (règle publique) afin de s'assurer que l'image du fournisseur a accès. Si cela entraîne une règle de sécurité inacceptable (comme cela peut être le cas avec les modifications apportées au servicemanager), une mise à niveau du fournisseur peut être forcée.
Classe/Autorisations supprimées
Ce scénario se produit lorsqu'un gestionnaire d'objets est supprimé (par exemple, le gestionnaire d'objets ZygoteConnection
) et ne devrait pas poser de problème. La classe et les autorisations du gestionnaire d'objets peuvent rester définies dans la stratégie jusqu'à ce que la version du fournisseur ne les utilise plus. Pour ce faire, ajoutez les définitions au fichier de mappage correspondant.
Personnalisation du fournisseur pour les nouveaux types ou ceux renommés
Les nouveaux types de fournisseurs sont au cœur du développement des règles des fournisseurs, car ils sont nécessaires pour décrire les nouveaux processus, binaires, appareils, sous-systèmes et données stockées. Il est donc impératif d'autoriser la création de types définis par le fournisseur.
Étant donné que la stratégie du fournisseur est toujours la plus ancienne sur l'appareil, il n'est pas nécessaire de convertir automatiquement tous les types de fournisseurs en attributs dans la stratégie. La plate-forme ne s'appuie sur rien de ce qui est libellé dans la stratégie du fournisseur, car elle n'en a aucune connaissance. Toutefois, elle fournit les attributs et les types publics qu'elle utilise pour interagir avec les objets libellés avec ces types (par exemple, domain
, sysfs_type
, etc.). Pour que la plate-forme continue d'interagir correctement avec ces objets, les attributs et les types doivent être appliqués de manière appropriée, et des règles spécifiques peuvent devoir être ajoutées aux domaines personnalisables (comme init
).
Modifications d'attributs pour Android 9
Les appareils qui passent à Android 9 peuvent utiliser les attributs suivants, mais les appareils qui démarrent avec Android 9 ne doivent pas le faire.
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 entrevendor
etcoredomains
. Les processus de la plate-forme et des fournisseurs 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
system_executes_vendor_violators
: attribut pour tous les domaines système (à l'exception deinit
etshell domains
) qui ne respectent pas l'exigence consistant à 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
coredomains
qui ont besoin d'accéder aux binaires du fournisseur doivent être déplacés vers la partition du fournisseur et ne plus être descoredomain
.
- 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, sauf ceux considérés comme suffisamment sécurisés pour être accessibles à partir de ces applications (voir les services sécurisés ci-dessous). Deux raisons principales expliquent cette situation:
- Les serveurs HwBinder n'effectuent pas d'authentification client, car HIDL n'expose actuellement pas les informations d'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, par mesure de précaution, on suppose par défaut 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 présentant un taux d'incidence des problèmes de sécurité plus élevé que les composants
system/core
et 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 sécurisés
Les services sécurisés incluent les suivants:
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 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 de liaisonsurfaceflinger
, auquel les applications sont autorisées à accéder.hal_omx_hwservice
. Il s'agit d'une version HwBinder du service de liaisonmediacodec
, 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
non considérés comme sécurisés disposent de l'attribut untrusted_app_visible_hwservice
. Les serveurs HAL correspondants disposent de l'attribut untrusted_app_visible_halserver
. Les appareils qui démarrent avec Android 9 NE DOIVENT PAS utiliser l'attribut untrusted
.
Recommandation :
- Les applications non approuvées 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
vendor
doivent disposer de leur propre domaine de stratégie de sécurité défini par le fournisseur.
Tests des attributs de fichier
Android 9 inclut des tests au moment de la compilation qui garantissent que tous les fichiers situés dans des emplacements spécifiques disposent des attributs appropriés (par exemple, que tous les fichiers de sysfs
disposent de l'attribut sysfs_type
requis).
Politique publique de la plate-forme
La stratégie publique de la plate-forme est au cœur de la conformité au modèle d'architecture Android 8.0, sans simplement maintenir l'union des stratégies de plate-forme de la version 1 et de la version 2. Les fournisseurs sont exposés à un sous-ensemble de règles de plate-forme qui contient des types et des attributs utilisables, ainsi que des règles sur ces types et attributs, qui font ensuite partie de la stratégie du fournisseur (c'est-à-dire vendor_sepolicy.cil
).
Les types et les règles sont automatiquement traduits dans la règle générée par le fournisseur en attribute_vN
, de sorte que tous les types fournis par la plate-forme soient des attributs avec version (mais les attributs ne sont pas versionnés). La plate-forme est chargée de mapper les types concrets qu'elle fournit dans les attributs appropriés pour s'assurer que la stratégie du fournisseur continue de fonctionner et que les règles fournies pour une version particulière sont incluses. La combinaison de la règle publique de la plate-forme et de la règle du fournisseur répond à l'objectif du modèle d'architecture Android 8.0, qui consiste à autoriser les builds de plate-forme et de fournisseur indépendants.
Mappage sur des chaînes d'attributs
Lorsque vous utilisez des attributs pour mapper des versions de règles, un type est mappé sur un attribut ou plusieurs attributs, ce qui garantit que les objets libellés avec le type sont accessibles via les attributs correspondant à leurs types précédents.
Pour atteindre l'objectif de masquer les informations de version à l'auteur de la règle, vous devez générer automatiquement les attributs avec version et les attribuer aux types appropriés. Dans le cas courant des types statiques, c'est simple : type_foo
est mappé sur type_foo_v1
.
Pour une modification de libellé d'objet telle que sysfs
→ sysfs_A
ou mediaserver
→ audioserver
, la création de ce mappage n'est pas triviale (et est décrite dans les exemples ci-dessus). Les responsables de la gestion des règles de la plate-forme doivent déterminer comment créer le mappage aux points de transition des objets, ce qui nécessite de comprendre la relation entre les objets et les libellés qui leur sont attribués, et de déterminer quand cela se produit. Pour assurer la rétrocompatibilité, cette complexité doit être gérée du côté de la plate-forme, qui est la seule partition pouvant être mise à niveau.
Versions antérieures
Par souci de simplicité, la plate-forme Android publie une version de sepolicy lorsqu'une nouvelle branche de version est créée. Comme décrit ci-dessus, le numéro de version est contenu dans PLATFORM_SEPOLICY_VERSION
et se présente sous la forme MM.nn
, où MM
correspond à la valeur du SDK et nn
est une valeur privée gérée dans /platform/system/sepolicy.
. Par exemple, 19.0
pour Kitkat, 21.0
pour Lollipop, 22.0
pour Lollipop-MR1, 23.0
pour Marshmallow, 24.0
pour Nougat, 25.0
pour Nougat-MR1, 26.0
pour Oreo, 27.0
pour Oreo-MR1 et 28.0
pour Android 9.
Les valeurs Uprev ne sont pas toujours des nombres entiers. Par exemple, si une mise à niveau de MR vers une version nécessite une modification incompatible dans system/sepolicy/public
, mais pas une mise à niveau de l'API, cette version de sepolicy peut être: vN.1
. La version présente dans une branche de développement est une 10000.0
qui ne doit jamais être utilisée dans les appareils commercialisés.
Android peut abandonner la version la plus ancienne lors de la mise à niveau. Pour obtenir des informations sur le moment où une version doit être abandonnée, Android peut collecter le nombre d'appareils exécutant cette version d'Android avec des règles du fournisseur et qui reçoivent toujours des mises à jour majeures de la plate-forme. Si le nombre est inférieur à un certain seuil, cette version est obsolète.
Impact sur les performances de plusieurs attributs
Comme décrit sur https://github.com/SELinuxProject/cil/issues/9, un grand nombre d'attributs attribués à un type entraîne des problèmes de performances en cas d'échec du cache de règles.
Il s'agissait d'un problème confirmé dans Android. Des modifications ont donc été apportées à Android 8.0 pour supprimer les attributs ajoutés à la stratégie par le compilateur de règles, ainsi que les attributs inutilisés. Ces modifications ont résolu les régressions de performances.
Règles publiques sur les produits et le 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 du fournisseur. Comme pour la politique publique de la plate-forme, le fournisseur utilise des types et des règles automatiquement traduits en attributs avec version, par exemple, de type
en type_N
, où N
est la version de la plate-forme sur laquelle la partition du fournisseur est compilée.
Lorsque les partitions system_ext
et product
sont basées sur la même version de plate-forme N
, le système de compilation génère des fichiers de mappage de base pour system_ext/etc/selinux/mapping/N.cil
et product/etc/selinux/mapping/N.cil
, qui contiennent des mappages d'identité de type
à type_N
. Le fournisseur peut accéder à type
avec l'attribut type_N
versionné.
Si seules les partitions system_ext
et product
sont mises à jour, par exemple de N
à N+1
(ou version ultérieure), tandis que le fournisseur reste sur N
, il risque de perdre l'accès aux types des partitions system_ext
et product
. Pour éviter les erreurs, les partitions system_ext
et product
doivent fournir des fichiers de mappage de types concrets vers des attributs type_N
. Chaque partenaire est responsable de la gestion des fichiers de mappage s'il prend en charge le fournisseur N
avec des partitions system_ext
et product
N+1
(ou version ultérieure).
Pour ce faire, les partenaires doivent:
- Copiez les fichiers de mappage de base générés à partir des partitions
N
,system_ext
etproduct
sur leur arbre source. - Modifiez les fichiers de mappage si nécessaire.
-
Installez les fichiers de mappage dans les partitions
system_ext
etproduct
deN+1
(ou version ultérieure).
Par exemple, supposons que N
system_ext
possède un type public nommé foo_type
. system_ext/etc/selinux/mapping/N.cil
dans la partition system_ext
N
se présente alors comme suit:
(typeattributeset foo_type_N (foo_type)) (expandtypeattribute foo_type_N true) (typeattribute foo_type_N)
Si bar_type
est ajouté à N+1
system_ext et si bar_type
doit être mappé sur foo_type
pour le fournisseur N
, N.cil
peut être mis à jour à partir de
(typeattributeset foo_type_N (foo_type))
to
(typeattributeset foo_type_N (foo_type bar_type))
et est ensuite installé dans la partition system_ext de N+1
.
Le fournisseur N
peut continuer à accéder aux foo_type
et bar_type
de system_ext.N+1
Libellés des contextes SELinux
Pour distinguer la plate-forme de la politique de sécurité 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 les frais de compilation supplémentaires sur l'appareil au démarrage,
file_contexts
cesse d'exister sous forme binaire. Il s'agit plutôt d'un fichier texte d'expression régulière lisible, tel que{property, service}_contexts
(comme c'était le cas avant la version 7.0). - Les
file_contexts
sont répartis entre deux fichiers :plat_file_contexts
- Plate-forme Android
file_context
qui ne comporte pas de libellés spécifiques à l'appareil, sauf pour l'étiquetage de parties de la partition/vendor
qui doivent être étiquetées avec précision pour assurer le bon fonctionnement des fichiers sepolicy. - Doit se trouver dans la partition
system
à/system/etc/selinux/plat_file_contexts
sur l'appareil et être chargé parinit
au début avec le fournisseurfile_context
.
- Plate-forme Android
vendor_file_contexts
file_context
spécifique à l'appareil créé en combinant lesfile_contexts
trouvés dans les répertoires pointés parBOARD_SEPOLICY_DIRS
dans les fichiersBoardconfig.mk
de l'appareil.- Doit être installé à
/vendor/etc/selinux/vendor_file_contexts
dans la partitionvendor
et être chargé parinit
au début avec la plate-formefile_context
.
Contextes de propriété
Dans Android 8.0, property_contexts
est divisé en deux fichiers:
plat_property_contexts
property_context
de la plate-forme Android qui ne comporte pas de libellés spécifiques à l'appareil.- Doit se trouver dans la partition
system
à l'emplacement/system/etc/selinux/plat_property_contexts
et être chargé parinit
au début, avec le fournisseurproperty_contexts
.
vendor_property_contexts
property_context
spécifique à l'appareil créé en combinant lesproperty_contexts
trouvés dans les répertoires pointés parBOARD_SEPOLICY_DIRS
dans les fichiersBoardconfig.mk
de l'appareil.- Doit se trouver dans la partition
vendor
à l'emplacement/vendor/etc/selinux/vendor_property_contexts
et être chargé parinit
au début avec la plate-formeproperty_context
Contextes de service
Dans Android 8.0, service_contexts
est divisé entre les fichiers suivants:
plat_service_contexts
service_context
spécifique à la plate-forme Android pour leservicemanager
.service_context
ne comporte pas d'étiquettes spécifiques à l'appareil.- Doit se trouver dans la partition
system
à l'emplacement/system/etc/selinux/plat_service_contexts
et être chargé parservicemanager
au début, avec le fournisseurservice_contexts
.
vendor_service_contexts
service_context
spécifique à l'appareil créé en combinant lesservice_contexts
trouvés dans les répertoires pointés parBOARD_SEPOLICY_DIRS
dans les fichiersBoardconfig.mk
de l'appareil.- Doit se trouver dans la partition
vendor
à l'emplacement/vendor/etc/selinux/vendor_service_contexts
et être chargé parservicemanager
au début avec la plate-formeservice_contexts
. - Bien que
servicemanager
recherche ce fichier au démarrage, pour un appareilTREBLE
entièrement conforme,vendor_service_contexts
NE DOIT PAS exister. En effet, toutes les interactions entre les processusvendor
etsystem
DOIVENT passer parhwservicemanager
/hwbinder
.
plat_hwservice_contexts
hwservice_context
de la plate-forme Android pourhwservicemanager
qui ne comporte pas d'étiquettes spécifiques à l'appareil.- Doit se trouver dans la partition
system
à l'emplacement/system/etc/selinux/plat_hwservice_contexts
et être chargé parhwservicemanager
au début avecvendor_hwservice_contexts
.
vendor_hwservice_contexts
hwservice_context
spécifique à l'appareil créé en combinant leshwservice_contexts
trouvés dans les répertoires pointés parBOARD_SEPOLICY_DIRS
dans les fichiersBoardconfig.mk
de l'appareil.- Doit se trouver dans la partition
vendor
à l'emplacement/vendor/etc/selinux/vendor_hwservice_contexts
et être chargé parhwservicemanager
au début avecplat_service_contexts
.
vndservice_contexts
service_context
spécifique à l'appareil pour levndservicemanager
créé en combinant lesvndservice_contexts
trouvés dans les répertoires pointés parBOARD_SEPOLICY_DIRS
dans leBoardconfig.mk
de l'appareil.- Ce fichier doit se trouver dans la partition
vendor
à l'emplacement/vendor/etc/selinux/vndservice_contexts
et être chargé parvndservicemanager
au démarrage.
Contextes Seapp
Dans Android 8.0, seapp_contexts
est divisé en deux fichiers:
plat_seapp_contexts
- Plate-forme Android
seapp_context
sans modification spécifique à l'appareil. - Doit se trouver dans la partition
system
à l'emplacement/system/etc/selinux/plat_seapp_contexts.
- Plate-forme Android
vendor_seapp_contexts
- Extension spécifique à l'appareil de la plate-forme
seapp_context
créée en combinant lesseapp_contexts
trouvés dans les répertoires pointés parBOARD_SEPOLICY_DIRS
dans les fichiersBoardconfig.mk
de l'appareil. - Doit se trouver dans la partition
vendor
à l'emplacement/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.xml
sans modification spécifique à l'appareil. - Doit se trouver dans la partition
system
à l'emplacement/system/etc/selinux/.
- Plate-forme Android
mac_permissions.xml
non lié à la plate-forme- Extension spécifique à l'appareil de la plate-forme
mac_permissions.xml
créée à partir demac_permissions.xml
trouvée dans les répertoires pointés parBOARD_SEPOLICY_DIRS
dans les fichiersBoardconfig.mk
de l'appareil. - Doit se trouver dans la partition
vendor
à l'emplacement/vendor/etc/selinux/.
- Extension spécifique à l'appareil de la plate-forme