Personnaliser SELinux

Une fois que vous avez intégré le niveau de base de la fonctionnalité SELinux et analysé minutieusement les résultats, vous pouvez ajouter vos propres paramètres de stratégie pour couvrir vos personnalisations du système d'exploitation Android. Ces règles doivent toujours respecter les exigences du programme de compatibilité Android et ne doivent pas supprimer les paramètres SELinux par défaut.

Les fabricants ne doivent pas supprimer la règle SELinux existante. Sinon, ils risquent de perturber l'implémentation SELinux d'Android et les applications qu'elle régit. Cela inclut les applications tierces qui devront probablement être améliorées pour être conformes et opérationnelles. Les applications ne doivent nécessiter aucune modification pour continuer à fonctionner sur les appareils compatibles avec SELinux.

Lorsque vous commencez à personnaliser SELinux, n'oubliez pas les points suivants:

  • Écrire une stratégie SELinux pour tous les nouveaux daemons
  • Utiliser des domaines prédéfinis lorsque cela est approprié
  • Attribuer un domaine à tout processus créé en tant que service init
  • Familiarisez-vous avec les macros avant d'écrire une règle
  • Envoyer les modifications apportées au règlement principal dans AOSP

Et n'oubliez pas:

  • Créer une règle incompatible
  • Autoriser la personnalisation des règles pour les utilisateurs finaux
  • Autoriser les personnalisations des stratégies MDM
  • Effrayer les utilisateurs en cas de non-respect des règles
  • Ajouter des portes dérobées

Pour connaître les exigences spécifiques, consultez la section Fonctionnalités de sécurité du noyau du document de définition de la compatibilité Android.

SELinux utilise une approche de liste blanche, ce qui signifie que tous les accès doivent être explicitement autorisés dans la règle pour être accordés. Étant donné que la stratégie SELinux par défaut d'Android est déjà compatible avec le projet Android Open Source, vous n'êtes pas tenu de modifier les paramètres SELinux de quelque manière que ce soit. Si vous personnalisez les paramètres SELinux, veillez à ne pas endommager les applications existantes. Pour commencer :

  1. Utilisez le noyau Android le plus récent.
  2. Adoptez le principe du moindre privilège.
  3. Ne traitez que vos propres ajouts à Android. La règle par défaut fonctionne automatiquement avec le codebase du projet Open Source Android.
  4. Compartimentez les composants logiciels en modules qui effectuent des tâches uniques.
  5. Créez des règles SELinux qui isolent ces tâches des fonctions sans rapport.
  6. Placez ces règles dans des fichiers *.te (extension des fichiers sources de règles SELinux) dans le répertoire /device/manufacturer/device-name/sepolicy et utilisez des variables BOARD_SEPOLICY pour les inclure dans votre build.
  7. Définissez les nouveaux domaines comme permissifs au départ. Pour ce faire, utilisez une déclaration permissive dans le fichier .te du domaine.
  8. Analysez les résultats et affinez vos définitions de domaine.
  9. Supprimez la déclaration permissive lorsqu'aucun autre refus ne s'affiche dans les builds userdebug.

Une fois que vous avez intégré votre modification de règle SELinux, ajoutez une étape à votre workflow de développement pour vous assurer de la compatibilité SELinux à l'avenir. Dans un processus de développement logiciel idéal, les règles SELinux ne changent que lorsque le modèle logiciel change, et non l'implémentation réelle.

Lorsque vous commencez à personnaliser SELinux, commencez par examiner les ajouts que vous avez effectués à Android. Si vous avez ajouté un composant qui exécute une nouvelle fonction, assurez-vous qu'il respecte les règles de sécurité d'Android, ainsi que toute stratégie associée élaborée par l'OEM, avant d'activer le mode d'application.

Pour éviter les problèmes inutiles, il est préférable d'être trop large et trop compatible que trop restrictif et incompatible, ce qui entraîne des dysfonctionnements des fonctions de l'appareil. À l'inverse, si vos modifications profiteront à d'autres utilisateurs, vous devez les envoyer à la règle SELinux par défaut en tant que correctif. Si le correctif est appliqué à la stratégie de sécurité par défaut, vous n'aurez pas besoin d'effectuer cette modification à chaque nouvelle version d'Android.

Exemples d'instructions de stratégie

SELinux est basé sur le langage informatique M4 et est donc compatible avec diverses macros pour gagner du temps.

Dans l'exemple suivant, tous les domaines sont autorisés à lire ou à écrire dans /dev/null et à lire dans /dev/zero.

# Allow read / write access to /dev/null
allow domain null_device:chr_file { getattr open read ioctl lock append write};

# Allow read-only access to /dev/zero
allow domain zero_device:chr_file { getattr open read ioctl lock };

La même instruction peut être écrite avec des macros *_file_perms SELinux (abréviation):

# Allow read / write access to /dev/null
allow domain null_device:chr_file rw_file_perms;

# Allow read-only access to /dev/zero
allow domain zero_device:chr_file r_file_perms;

Exemple de règle

Voici un exemple de stratégie complète pour DHCP, que nous examinons ci-dessous:

type dhcp, domain;
permissive dhcp;
type dhcp_exec, exec_type, file_type;
type dhcp_data_file, file_type, data_file_type;

init_daemon_domain(dhcp)
net_domain(dhcp)

allow dhcp self:capability { setgid setuid net_admin net_raw net_bind_service
};
allow dhcp self:packet_socket create_socket_perms;
allow dhcp self:netlink_route_socket { create_socket_perms nlmsg_write };
allow dhcp shell_exec:file rx_file_perms;
allow dhcp system_file:file rx_file_perms;
# For /proc/sys/net/ipv4/conf/*/promote_secondaries
allow dhcp proc_net:file write;
allow dhcp system_prop:property_service set ;
unix_socket_connect(dhcp, property, init)

type_transition dhcp system_data_file:{ dir file } dhcp_data_file;
allow dhcp dhcp_data_file:dir create_dir_perms;
allow dhcp dhcp_data_file:file create_file_perms;

allow dhcp netd:fd use;
allow dhcp netd:fifo_file rw_file_perms;
allow dhcp netd:{ dgram_socket_class_set unix_stream_socket } { read write };
allow dhcp netd:{ netlink_kobject_uevent_socket netlink_route_socket
netlink_nflog_socket } { read write };

Analysons cet exemple:

Sur la première ligne, la déclaration de type, le daemon DHCP hérite de la stratégie de sécurité de base (domain). Dans les exemples d'instructions précédents, le DHCP peut lire et écrire dans /dev/null.

Dans la deuxième ligne, DHCP est identifié comme un domaine permissif.

Sur la ligne init_daemon_domain(dhcp), la stratégie indique que le DHCP est généré à partir de init et qu'il est autorisé à communiquer avec lui.

Dans la ligne net_domain(dhcp), la stratégie permet à DHCP d'utiliser les fonctionnalités réseau courantes du domaine net, telles que la lecture et l'écriture de paquets TCP, la communication via des sockets et l'exécution de requêtes DNS.

Sur la ligne allow dhcp proc_net:file write;, la stratégie indique que le protocole DHCP peut écrire dans des fichiers spécifiques de /proc. Cette ligne illustre l'étiquetage précis des fichiers de SELinux. Il utilise le libellé proc_net pour limiter l'accès en écriture aux seuls fichiers sous /proc/sys/net.

Le dernier bloc de l'exemple commençant par allow dhcp netd:fd use; montre comment les applications peuvent être autorisées à interagir les unes avec les autres. La stratégie indique que DHCP et netd peuvent communiquer entre eux via des descripteurs de fichiers, des fichiers FIFO, des sockets de datagrammes et des sockets de flux UNIX. Le DHCP ne peut lire et écrire que depuis les sockets de datagramme et les sockets de flux UNIX, et ne peut pas les créer ni les ouvrir.

Commandes disponibles

Classe Autorisation
fichier
ioctl read write create getattr setattr lock relabelfrom relabelto append
unlink link rename execute swapon quotaon mounton
répertoire
add_name remove_name reparent search rmdir open audit_access execmod
socket
ioctl read write create getattr setattr lock relabelfrom relabelto append bind
connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg
name_bind
filesystem
mount remount unmount getattr relabelfrom relabelto transition associate
quotamod quotaget
processus
fork transition sigchld sigkill sigstop signull signal ptrace getsched setsched
getsession getpgid setpgid getcap setcap share getattr setexec setfscreate
noatsecure siginh setrlimit rlimitinh dyntransition setcurrent execmem
execstack execheap setkeycreate setsockcreate
sécurité
compute_av compute_create compute_member check_context load_policy
compute_relabel compute_user setenforce setbool setsecparam setcheckreqprot
read_policy
capacité
chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap
linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock
ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin
sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write
audit_control setfcap

PLUS

ET PLUS ENCORE

règles neverallow

Les règles neverallow SELinux interdisent les comportements qui ne devraient jamais se produire. Grâce aux tests de compatibilité, les règles neverallow SELinux sont désormais appliquées sur tous les appareils.

Les consignes suivantes visent à aider les fabricants à éviter les erreurs liées aux règles neverallow lors de la personnalisation. Les numéros de règle utilisés ici correspondent à Android 5.1 et sont susceptibles d'être modifiés avec chaque version.

Règle 48: neverallow { domain -debuggerd -vold -dumpstate -system_server } self:capability sys_ptrace;
Consultez la page de manuel de ptrace. La capacité sys_ptrace permet de ptrace n'importe quel processus, ce qui permet de contrôler de manière très précise les autres processus et ne doit appartenir qu'aux composants système désignés, décrits dans la règle. Le besoin de cette fonctionnalité indique souvent la présence d'un élément qui n'est pas destiné aux builds visibles par l'utilisateur ou d'une fonctionnalité qui n'est pas nécessaire. Supprimez le composant inutile.

Règle 76: neverallow { domain -appdomain -dumpstate -shell -system_server -zygote } { file_type -system_file -exec_type }:file execute;
Cette règle vise à empêcher l'exécution de code arbitraire sur le système. Plus précisément, il affirme que seul le code sur /system est exécuté, ce qui permet de garantir la sécurité grâce à des mécanismes tels que le démarrage validé. En cas de problème avec cette règle neverallow, la meilleure solution consiste souvent à déplacer le code incriminé vers la partition /system.

Personnaliser SEPolicy sous Android 8.0 ou version ultérieure

Cette section fournit des consignes concernant la stratégie SELinux du fournisseur dans Android 8.0 et versions ultérieures, y compris des informations sur SEPolicy et les extensions SEPolicy du projet Android Open Source (AOSP). Pour en savoir plus sur la compatibilité de la règle SELinux entre les partitions et les versions d'Android, consultez la page Compatibilité.

Emplacement de la stratégie

Sous Android 7.0 et versions antérieures, les fabricants d'appareils pouvaient ajouter des règles à BOARD_SEPOLICY_DIRS, y compris des règles destinées à renforcer les règles AOSP sur différents types d'appareils. Dans Android 8.0 et versions ultérieures, l'ajout d'une règle à BOARD_SEPOLICY_DIRS la place uniquement dans l'image du fournisseur.

Sur Android 8.0 et versions ultérieures, les règles se trouvent aux emplacements suivants dans AOSP:

  • system/sepolicy/public. Inclut la règle exportée pour être utilisée dans la règle spécifique au fournisseur. Tout est intégré à l'infrastructure de compatibilité d'Android 8.0. La stratégie publique est destinée à persister entre les versions. Vous pouvez donc inclure tout élément /public dans votre stratégie personnalisée. Par conséquent, le type de stratégie pouvant être placé dans /public est plus restreint. Considérez-la comme l'API de règles exportée de la plate-forme: tout ce qui concerne l'interface entre /system et /vendor appartient à cette catégorie.
  • system/sepolicy/private. Inclut les règles nécessaires au fonctionnement de l'image système, mais dont la stratégie d'image du fournisseur ne doit pas avoir connaissance.
  • system/sepolicy/vendor. Inclut la stratégie pour les composants qui se trouvent dans /vendor, mais qui existent dans l'arborescence de la plate-forme principale (et non dans les répertoires spécifiques à l'appareil). Il s'agit d'un artefact de la distinction entre les appareils et les composants globaux du système de compilation. Conceptuellement, il fait partie de la stratégie spécifique à l'appareil décrite ci-dessous.
  • device/manufacturer/device-name/sepolicy. Inclut les règles spécifiques à l'appareil. Inclut également les personnalisations de l'appareil pour la stratégie, qui, dans Android 8.0 et versions ultérieures, correspond à la stratégie pour les composants sur l'image du fournisseur.

Dans Android 11 et versions ultérieures, les partitions system_ext et produit peuvent également inclure des règles spécifiques aux partitions. Les règles system_ext et produit sont également divisées en règles publiques et privées, et les fournisseurs peuvent utiliser les règles publiques de system_ext et de produit, comme la règle système.

  • SYSTEM_EXT_PUBLIC_SEPOLICY_DIRS : inclut la règle exportée pour être utilisée dans la règle spécifique au fournisseur. Installé sur la partition system_ext.
  • SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS. Inclut la stratégie nécessaire au fonctionnement de l'image system_ext, mais dont la stratégie d'image du fournisseur ne doit pas avoir connaissance. Installé sur la partition system_ext.
  • PRODUCT_PUBLIC_SEPOLICY_DIRS : inclut la règle exportée pour être utilisée dans la règle spécifique au fournisseur. Installé dans la partition des produits.
  • PRODUCT_PRIVATE_SEPOLICY_DIRS. Inclut le règlement nécessaire au fonctionnement de l'image du produit, mais dont le règlement sur les images du fournisseur ne doit pas avoir connaissance. Installé sur la partition de produits.
Remarque:Lorsque GSI est utilisé, les partitions system_ext et product de l'OEM ne sont pas montées. Les règles du sepolicy du fournisseur qui utilisent la stratégie publique de produit et system_ext de l'OEM deviennent NOP, car les définitions de type spécifiques à l'OEM sont manquantes.
Remarque:Soyez particulièrement prudent lorsque vous utilisez les règles publiques system_ext et product. Les règles publiques agissent en tant qu'API exportée entre system_ext/product et le fournisseur. Les partenaires sont censés gérer eux-mêmes les problèmes de compatibilité.

Scénarios de stratégie compatibles

Sur les appareils lancés avec Android 8.0 ou version ultérieure, l'image du fournisseur doit fonctionner avec l'image système OEM et l'image système AOSP de référence fournie par Google (et passer le CTS sur cette image de référence). Ces exigences garantissent une séparation nette entre le framework et le code du fournisseur. Ces appareils sont compatibles avec les scénarios suivants.

extensions vendor-image-only

Exemple:Ajout d'un service à vndservicemanager à partir de l'image du fournisseur qui prend en charge les processus de l'image du fournisseur.

Comme pour les appareils lancés avec des versions Android précédentes, ajoutez la personnalisation spécifique à l'appareil dans device/manufacturer/device-name/sepolicy. La nouvelle règle régissant la façon dont les composants du fournisseur interagissent avec (uniquement) d'autres composants du fournisseur doit impliquer des types présents uniquement dans device/manufacturer/device-name/sepolicy. La stratégie écrite ici permet au code du fournisseur de fonctionner, ne sera pas mise à jour dans le cadre d'une mise à jour OTA du framework uniquement et est présente dans la stratégie combinée sur un appareil avec l'image système AOSP de référence.

Prise en charge de l'image du fournisseur pour fonctionner avec AOSP

Exemple:Ajout d'un nouveau processus (enregistré avec hwservicemanager à partir de l'image du fournisseur) qui implémente un HAL défini par AOSP.

Comme pour les appareils lancés avec des versions précédentes d'Android, effectuez la personnalisation spécifique à l'appareil dans device/manufacturer/device-name/sepolicy. La stratégie exportée dans le cadre de system/sepolicy/public/ est disponible et est fournie dans le cadre de la stratégie du fournisseur. Les types et attributs de la stratégie publique peuvent être utilisés dans de nouvelles règles dictant les interactions avec les nouveaux bits spécifiques au fournisseur, sous réserve des restrictions neverallow fournies. Comme dans le cas du fournisseur uniquement, la nouvelle stratégie ici ne sera pas mise à jour dans le cadre d'une mise à jour OTA du framework uniquement et sera présente dans la stratégie combinée sur un appareil avec l'image système AOSP de référence.

extensions système-image-only

Exemple:Ajout d'un service (enregistré auprès de servicemanager) auquel seuls d'autres processus de l'image système peuvent accéder.

Ajoutez cette stratégie à system/sepolicy/private. Vous pouvez ajouter des processus ou des objets supplémentaires pour activer des fonctionnalités dans une image système partenaire, à condition que ces nouveaux bits n'aient pas besoin d'interagir avec de nouveaux composants de l'image du fournisseur (plus précisément, ces processus ou objets doivent fonctionner entièrement sans la stratégie de l'image du fournisseur). La stratégie exportée par system/sepolicy/public est disponible ici, comme pour les extensions d'images du fournisseur uniquement. Cette règle fait partie de l'image système et peut être mise à jour dans une mise à jour OTA du framework uniquement, mais elle ne sera pas présente lorsque vous utiliserez l'image système AOSP de référence.

Extensions d'image du fournisseur qui diffusent des composants AOSP étendus

Exemple:nouveau HAL non AOSP à utiliser par les clients étendus qui existent également dans l'image système AOSP (tel qu'un système_server étendu).

La stratégie d'interaction entre le système et le fournisseur doit être incluse dans le répertoire device/manufacturer/device-name/sepolicy fourni sur la partition du fournisseur. Ce scénario est semblable au scénario ci-dessus qui consiste à ajouter la prise en charge des images de fournisseur pour fonctionner avec l'image de référence AOSP, à la différence que les composants AOSP modifiés peuvent également nécessiter une règle supplémentaire pour fonctionner correctement avec le reste de la partition système (ce qui est acceptable tant qu'ils disposent toujours des libellés de type AOSP publics).

La stratégie d'interaction des composants AOSP publics avec les extensions réservées aux images système doit se trouver dans system/sepolicy/private.

les extensions d'image système qui n'accèdent qu'aux interfaces AOSP ;

Exemple:Un nouveau processus système non AOSP doit accéder à un HAL sur lequel AOSP s'appuie.

Cette méthode est semblable à l'exemple d'extension d'image système uniquement, si ce n'est que les nouveaux composants système peuvent interagir sur l'interface system/vendor. La stratégie du nouveau composant système doit se trouver dans system/sepolicy/private, ce qui est acceptable à condition qu'elle soit via une interface déjà établie par AOSP dans system/sepolicy/public (c'est-à-dire que les types et attributs requis pour la fonctionnalité sont présents). Bien que la stratégie puisse être incluse dans la stratégie spécifique à l'appareil, elle ne pourra pas utiliser d'autres types system/sepolicy/private ni modifier (de quelque manière que ce soit) les règles en raison d'une mise à jour du framework uniquement. La règle peut être modifiée dans une mise à jour OTA du framework uniquement, mais elle ne sera pas présente lorsque vous utiliserez une image système AOSP (qui ne comportera pas non plus le nouveau composant système).

les extensions d'image du fournisseur qui diffusent de nouveaux composants système ;

Exemple:Ajout d'un nouveau HAL non AOSP à utiliser par un processus client sans analogue AOSP (et qui nécessite donc son propre domaine).

Comme dans l'exemple des extensions AOSP, le règlement des interactions entre le système et le fournisseur doit se trouver dans le répertoire device/manufacturer/device-name/sepolicy fourni sur la partition du fournisseur (pour s'assurer que le règlement du système n'a aucune connaissance des détails spécifiques au fournisseur). Vous pouvez ajouter de nouveaux types publics qui étendent la règle dans system/sepolicy/public. Cette opération ne doit être effectuée qu'en plus de la règle AOSP existante. Autrement dit, ne supprimez pas la règle publique AOSP. Les nouveaux types publics peuvent ensuite être utilisés pour les règles dans system/sepolicy/private et device/manufacturer/device-name/sepolicy.

N'oubliez pas que chaque ajout à system/sepolicy/public ajoute de la complexité en exposant une nouvelle garantie de compatibilité qui doit être suivie dans un fichier de mappage et qui est soumise à d'autres restrictions. Seuls les nouveaux types et les règles d'autorisation correspondantes peuvent être ajoutés dans system/sepolicy/public. Les attributs et les autres instructions de stratégie ne sont pas acceptés. De plus, les nouveaux types publics ne peuvent pas être utilisés pour étiqueter directement les objets dans la règle /vendor.

Scénarios de règles non compatibles

Les appareils équipés d'Android 8.0 ou version ultérieure ne sont pas compatibles avec le scénario de règle et les exemples suivants.

Extensions supplémentaires de l'image système nécessitant une autorisation pour les nouveaux composants de l'image du fournisseur après une mise à jour OTA du framework uniquement

Exemple:Un nouveau processus système non-AOSP nécessitant son propre domaine sera ajouté dans la prochaine version d'Android et doit accéder à un nouveau HAL non-AOSP.

Semblable à l'interaction entre le nouveau système (non-AOSP) et les composants du fournisseur, à l'exception du fait que le nouveau type de système est introduit dans une mise à jour OTA réservée au framework. Bien que le nouveau type puisse être ajouté à la règle dans system/sepolicy/public, la règle de fournisseur existante n'a aucune connaissance de ce nouveau type, car elle ne suit que la stratégie publique du système Android 8.0. AOSP gère cela en exposant les ressources fournies par le fournisseur via un attribut (par exemple, l'attribut hal_foo), mais comme les extensions de partenaires d'attributs ne sont pas compatibles avec system/sepolicy/public, cette méthode n'est pas disponible pour la stratégie du fournisseur. L'accès doit être fourni par un type public préexistant.

Exemple:Une modification apportée à un processus système (AOSP ou non-AOSP) doit modifier la façon dont il interagit avec le nouveau composant du fournisseur non-AOSP.

La règle appliquée à l'image système doit être écrite sans connaître les personnalisations spécifiques du fournisseur. Les règles concernant des interfaces spécifiques dans AOSP sont donc exposées via des attributs dans system/sepolicy/public, afin que la règle du fournisseur puisse accepter la future règle système qui utilise ces attributs. Toutefois, les extensions d'attributs dans system/sepolicy/public ne sont pas compatibles. Par conséquent, toutes les règles qui dictent comment les composants système interagissent avec les nouveaux composants du fournisseur (et qui ne sont pas gérées par les attributs déjà présents dans system/sepolicy/public AOSP) doivent se trouver dans device/manufacturer/device-name/sepolicy. Cela signifie que les types de système ne peuvent pas modifier l'accès autorisé aux types de fournisseurs dans le cadre d'une mise à jour OTA réservée au framework.