Compatibilité avec les règles

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 partition vendor. 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 partition vendor via le SEPolicy du fournisseur doivent avoir l'attribut vendor_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 partition vendor.
  • 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'étiquette sysfs_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.

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é de sysfs par sysfs_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 entre vendor et coredomains. 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.
  • system_executes_vendor_violators : attribut pour tous les domaines système (à l'exception de init et shell 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 des coredomain.

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:

  1. 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.
  2. 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 liaison surfaceflinger, auquel les applications sont autorisées à accéder.
  • hal_omx_hwservice. Il s'agit d'une version HwBinder du service de liaison mediacodec, auquel les applications sont autorisées à accéder.
  • hal_codec2_hwservice. Il s'agit d'une version plus récente de hal_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, puis mediaserver (qui est un binderservicedomain) communique à son tour avec hal_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 sysfssysfs_A ou mediaserveraudioserver, 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:

  1. Copiez les fichiers de mappage de base générés à partir des partitions N, system_ext et product sur leur arbre source.
  2. Modifiez les fichiers de mappage si nécessaire.
  3. Installez les fichiers de mappage dans les partitions system_ext et product de N+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é par init au début avec le fournisseur file_context.
    • vendor_file_contexts
      • file_context spécifique à l'appareil créé en combinant les file_contexts trouvés dans les répertoires pointés par BOARD_SEPOLICY_DIRS dans les fichiers Boardconfig.mk de l'appareil.
      • Doit être installé à /vendor/etc/selinux/vendor_file_contexts dans la partition vendor et être chargé par init au début avec la plate-forme file_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é par init au début, avec le fournisseur property_contexts.
  • vendor_property_contexts
    • property_context spécifique à l'appareil créé en combinant les property_contexts trouvés dans les répertoires pointés par BOARD_SEPOLICY_DIRS dans les fichiers Boardconfig.mk de l'appareil.
    • Doit se trouver dans la partition vendor à l'emplacement /vendor/etc/selinux/vendor_property_contexts et être chargé par init au début avec la plate-forme property_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 le servicemanager. 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é par servicemanager au début, avec le fournisseur service_contexts.
  • vendor_service_contexts
    • service_context spécifique à l'appareil créé en combinant les service_contexts trouvés dans les répertoires pointés par BOARD_SEPOLICY_DIRS dans les fichiers Boardconfig.mk de l'appareil.
    • Doit se trouver dans la partition vendor à l'emplacement /vendor/etc/selinux/vendor_service_contexts et être chargé par servicemanager au début avec la plate-forme service_contexts.
    • Bien que servicemanager recherche ce fichier au démarrage, pour un appareil TREBLE entièrement conforme, vendor_service_contexts NE DOIT PAS exister. En effet, toutes les interactions entre les processus vendor et system DOIVENT passer par hwservicemanager/hwbinder.
  • plat_hwservice_contexts
    • hwservice_context de la plate-forme Android pour hwservicemanager 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é par hwservicemanager au début avec vendor_hwservice_contexts.
  • vendor_hwservice_contexts
    • hwservice_context spécifique à l'appareil créé en combinant les hwservice_contexts trouvés dans les répertoires pointés par BOARD_SEPOLICY_DIRS dans les fichiers Boardconfig.mk de l'appareil.
    • Doit se trouver dans la partition vendor à l'emplacement /vendor/etc/selinux/vendor_hwservice_contexts et être chargé par hwservicemanager au début avec plat_service_contexts.
  • vndservice_contexts
    • service_context spécifique à l'appareil pour le vndservicemanager créé en combinant les vndservice_contexts trouvés dans les répertoires pointés par BOARD_SEPOLICY_DIRS dans le Boardconfig.mk de l'appareil.
    • Ce fichier doit se trouver dans la partition vendor à l'emplacement /vendor/etc/selinux/vndservice_contexts et être chargé par vndservicemanager 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.
  • vendor_seapp_contexts
    • Extension spécifique à l'appareil de la plate-forme seapp_context créée en combinant les seapp_contexts trouvés dans les répertoires pointés par BOARD_SEPOLICY_DIRS dans les fichiers Boardconfig.mk de l'appareil.
    • Doit se trouver dans la partition vendor à l'emplacement /vendor/etc/selinux/vendor_seapp_contexts.

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/.
  • mac_permissions.xml non lié à la plate-forme
    • Extension spécifique à l'appareil de la plate-forme mac_permissions.xml créée à partir de mac_permissions.xml trouvée dans les répertoires pointés par BOARD_SEPOLICY_DIRS dans les fichiers Boardconfig.mk de l'appareil.
    • Doit se trouver dans la partition vendor à l'emplacement /vendor/etc/selinux/.