Personnalisation de SELinux

Après avoir intégré le niveau de base des fonctionnalités 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 politiques doivent toujours répondre aux 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 politique SELinux existante. Sinon, ils risquent de casser l'implémentation d'Android SELinux 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 SELinux.

Lorsque vous vous lancez dans la personnalisation de SELinux, n'oubliez pas de :

  • Écrivez la politique SELinux pour tous les nouveaux démons
  • Utilisez des domaines prédéfinis chaque fois que cela est approprié
  • Attribuez un domaine à tout processus généré en tant que service init
  • Familiarisez-vous avec les macros avant de rédiger une politique
  • Soumettre les modifications apportées à la politique principale à l'AOSP

Et n'oubliez pas de ne pas :

  • Créer une stratégie incompatible
  • Autoriser la personnalisation des politiques de l'utilisateur final
  • Autoriser les personnalisations de stratégie MDM
  • Effrayer les utilisateurs en cas de violations des règles
  • Ajouter des portes dérobées

Consultez la section Fonctionnalités de sécurité du noyau du document Définition de la compatibilité Android pour connaître les exigences spécifiques.

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

  1. Utilisez le dernier noyau Android .
  2. Adoptez le principe du moindre privilège .
  3. Adressez-vous uniquement à vos propres ajouts à Android. La stratégie par défaut fonctionne automatiquement avec la base de code du projet Android Open Source .
  4. Compartimentez les composants logiciels en modules qui effectuent des tâches uniques.
  5. Créez des politiques SELinux qui isolent ces tâches des fonctions non liées.
  6. Placez ces politiques dans des fichiers *.te (l'extension des fichiers source de politique SELinux) dans le répertoire /device/ manufacturer / device-name /sepolicy et utilisez les variables BOARD_SEPOLICY pour les inclure dans votre build.
  7. Rendre les nouveaux domaines permissifs dans un premier temps. Cela se fait en utilisant 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 n'apparaît dans les versions userdebug.

Après avoir intégré votre changement de politique SELinux, ajoutez une étape à votre flux de travail de développement pour garantir la compatibilité SELinux à l'avenir. Dans un processus de développement logiciel idéal, la politique SELinux ne change que lorsque le modèle logiciel change et non la mise en œuvre réelle.

Lorsque vous commencez à personnaliser SELinux, vérifiez d'abord vos ajouts à Android. Si vous avez ajouté un composant qui exécute une nouvelle fonction, assurez-vous que le composant respecte la politique de sécurité d'Android, ainsi que toute politique associée élaborée par l'OEM, avant d'activer le mode d'application.

Pour éviter des problèmes inutiles, il est préférable d'être trop large et trop compatible plutôt que trop restrictif et incompatible, ce qui entraîne des fonctions de l'appareil interrompues. À l'inverse, si vos modifications bénéficieront à d'autres, vous devez soumettre les modifications à la politique SELinux par défaut sous forme de correctif . Si le correctif est appliqué à la politique de sécurité par défaut, vous n'aurez pas besoin d'effectuer cette modification à chaque nouvelle version d'Android.

Exemples de déclarations de politique

SELinux est basé sur le langage informatique M4 et prend donc en charge une variété de macros pour gagner du temps.

Dans l'exemple suivant, tous les domaines ont accès à la lecture ou à l'écriture dans /dev/null et à la lecture à partir de /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 };

Cette même instruction peut être écrite avec les macros SELinux *_file_perms (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 politique

Voici un exemple complet de politique 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 };

Découpons l'exemple :

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

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

Dans la ligne init_daemon_domain(dhcp) , la stratégie indique que DHCP est généré à partir d' init et est autorisé à communiquer avec lui.

Dans la ligne net_domain(dhcp) , la stratégie permet à DHCP d'utiliser les fonctionnalités réseau communes 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.

Dans la ligne allow dhcp proc_net:file write; , la politique indique que DHCP peut écrire dans des fichiers spécifiques dans /proc . Cette ligne démontre l'étiquetage fin des fichiers de SELinux. Il utilise l'étiquette proc_net pour limiter l'accès en écriture uniquement aux fichiers sous /proc/sys/net .

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

Contrôles disponibles

Classe Autorisation
déposer
ioctl read write create getattr setattr lock relabelfrom relabelto append
unlink link rename execute swapon quotaon mounton
annuaire
add_name remove_name reparent search rmdir open audit_access execmod
prise
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
système de fichiers
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
aptitude
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

règles ne jamais autoriser

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

Les directives suivantes sont destinées à aider les fabricants à éviter les erreurs liées aux règles neverallow lors de la personnalisation. Les numéros de règles utilisés ici correspondent à Android 5.1 et sont susceptibles d'être modifiés selon les versions.

Règle 48 : neverallow { domain -debuggerd -vold -dumpstate -system_server } self:capability sys_ptrace;
Consultez la page de manuel pour ptrace . La fonctionnalité sys_ptrace donne la possibilité de ptrace n'importe quel processus, ce qui permet un grand contrôle sur les autres processus et ne doit appartenir qu'aux composants système désignés, décrits dans la règle. La nécessité de cette fonctionnalité indique souvent la présence de quelque chose qui n'est pas destiné aux versions destinées aux utilisateurs ou de fonctionnalités qui ne sont pas nécessaires. 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 a pour but d'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 des garanties de sécurité grâce à des mécanismes tels que le démarrage vérifié. Souvent, la meilleure solution lorsque vous rencontrez un problème avec cette règle neverallow est de déplacer le code incriminé vers la partition /system .

Personnalisation de SEPolicy dans Android 8.0+

Cette section fournit des directives pour la politique SELinux du fournisseur dans Android 8.0 et versions ultérieures, y compris des détails sur les extensions SEPolicy et SEPolicy du projet Android Open Source (AOSP). Pour plus d'informations sur la façon dont la stratégie SELinux reste compatible entre les partitions et les versions d'Android, consultez Compatibilité .

Placement de la politique

Dans Android 7.0 et versions antérieures, les fabricants d'appareils pouvaient ajouter une stratégie à BOARD_SEPOLICY_DIRS , y compris une stratégie destinée à augmenter la stratégie AOSP sur différents types d'appareils. Sous Android 8.0 et versions ultérieures, l'ajout d'une stratégie à BOARD_SEPOLICY_DIRS place la stratégie uniquement dans l'image du fournisseur.

Sous Android 8.0 et versions ultérieures, la stratégie existe aux emplacements suivants dans AOSP :

  • système/sépolitique/public . Inclut la stratégie exportée pour être utilisée dans la stratégie spécifique au fournisseur. Tout se passe dans l' infrastructure de compatibilité Android 8.0. La politique publique est censée persister dans toutes les versions afin que vous puissiez inclure n'importe quel élément /public dans votre politique personnalisée. Pour cette raison, le type de stratégie pouvant être placée dans /public est plus restreint. Considérez ceci comme l'API de politique exportée par la plateforme : tout ce qui concerne l'interface entre /system et /vendor appartient ici.
  • système/sepolicy/privé . Inclut la stratégie nécessaire au fonctionnement de l’image système, mais dont la stratégie d’image du fournisseur ne devrait pas avoir connaissance.
  • système/sepolicy/fournisseur . Inclut une stratégie pour les composants qui vont dans /vendor mais qui existent dans l'arborescence principale de la plate-forme (et non dans les répertoires spécifiques au périphérique). Il s'agit d'un artefact de la distinction du système de construction entre les périphériques et les composants globaux ; Conceptuellement, cela fait partie de la politique spécifique à l'appareil décrite ci-dessous.
  • appareil/ manufacturer / device-name /sepolicy . Inclut une stratégie spécifique à l’appareil. Inclut également les personnalisations de la stratégie de l'appareil, qui, dans Android 8.0 et versions ultérieures, correspond à la stratégie relative aux composants sur l'image du fournisseur.

Sous Android 11 et versions ultérieures, les partitions system_ext et product peuvent également inclure des stratégies spécifiques aux partitions. system_ext et les stratégies produit sont également divisées en publiques et privées, et les fournisseurs peuvent utiliser les stratégies publiques de system_ext et du produit, comme la stratégie système.

  • SYSTEM_EXT_PUBLIC_SEPOLICY_DIRS . Inclut la stratégie exportée pour être utilisée dans la stratégie 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 devrait avoir aucune connaissance. Installé sur la partition system_ext.
  • PRODUCT_PUBLIC_SEPOLICY_DIRS . Inclut la stratégie exportée pour être utilisée dans la stratégie spécifique au fournisseur. Installé sur la partition du produit.
  • PRODUCT_PRIVATE_SEPOLICY_DIRS . Inclut la politique nécessaire au fonctionnement de l'image du produit, mais dont la politique d'image du fournisseur ne devrait pas avoir connaissance. Installé sur la partition du produit.
Remarque : lorsque GSI est utilisé, les partitions system_ext et produit OEM ne seront pas montées. Les règles de la stratégie du fournisseur qui utilise la stratégie publique system_ext et produit du OEM deviennent NOP car les définitions de type spécifiques à l'OEM sont manquantes.
Remarque : Soyez très prudent lorsque vous utilisez system_ext et les politiques publiques du produit. Les politiques publiques agissent comme une 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 pris en charge

Sur les appareils lancés avec Android 8.0 et versions ultérieures, l'image du fournisseur doit fonctionner avec l'image système OEM et l'image système AOSP de référence fournies par Google (et transmettre 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 prennent en charge les scénarios suivants.

extensions réservées aux images du fournisseur

Exemple : ajout d'un nouveau 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 les versions précédentes d'Android, ajoutez une personnalisation spécifique à l'appareil dans device/ manufacturer / device-name /sepolicy . La nouvelle politique régissant la manière dont les composants du fournisseur interagissent avec (uniquement) d'autres composants du fournisseur devrait impliquer des types présents uniquement dans device/ manufacturer / device-name /sepolicy . La politique écrite ici permet au code du fournisseur de fonctionner, ne sera pas mise à jour dans le cadre d'un OTA uniquement framework et sera présente dans la politique combinée sur un appareil avec l'image système de référence AOSP.

prise en charge de l'image du fournisseur pour travailler avec AOSP

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

Comme pour les appareils lancés avec les versions précédentes d'Android, effectuez une 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 pour utilisation et est expédiée dans le cadre de la stratégie du fournisseur. Les types et attributs de la politique 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’un OTA uniquement cadre et sera présente dans la stratégie combinée sur un appareil avec l’image système AOSP de référence.

extensions d'image système uniquement

Exemple : ajout d'un nouveau service (enregistré auprès de servicemanager) accessible uniquement par d'autres processus à partir de l'image système.

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 sur l'image du fournisseur (en particulier, ces processus ou objets doivent fonctionner pleinement sans politique de l'image du fournisseur). . La politique exportée par system/sepolicy/public est disponible ici, tout comme pour les extensions d'image du fournisseur uniquement. Cette politique fait partie de l'image système et pourrait être mise à jour dans un OTA uniquement framework, mais ne sera pas présente lors de l'utilisation de l'image système AOSP de référence.

extensions d'image de fournisseur qui servent des composants AOSP étendus

Exemple : un nouveau HAL non-AOSP destiné à être utilisé par les clients étendus qui existent également dans l'image système AOSP (comme un serveur_système é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. Ceci est similaire au scénario ci-dessus consistant à ajouter la prise en charge de l'image du fournisseur pour fonctionner avec l'image AOSP de référence, sauf que les composants AOSP modifiés peuvent également nécessiter une stratégie supplémentaire pour fonctionner correctement avec le reste de la partition système (ce qui est bien tant qu'ils restent avoir les étiquettes de type AOSP publiques).

La politique d'interaction des composants AOSP publics avec les extensions d'image système uniquement doit être dans system/sepolicy/private .

extensions d'image système qui accèdent uniquement aux interfaces AOSP

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

Ceci est similaire à l' exemple d'extension d'image système uniquement , sauf que de nouveaux composants système peuvent interagir via l'interface system/vendor . La politique du nouveau composant système doit être placée dans system/sepolicy/private , ce qui est acceptable à condition qu'elle passe par une interface déjà établie par AOSP dans system/sepolicy/public (c'est-à-dire que les types et attributs requis pour la fonctionnalité sont là). Bien que la politique puisse être incluse dans la politique spécifique à l'appareil, elle ne pourrait pas utiliser d'autres types system/sepolicy/private ou être modifiée (de quelque manière que ce soit affectant la politique) à la suite d'une mise à jour du framework uniquement. La politique peut être modifiée dans un OTA framework uniquement, mais ne sera pas présente lors de l'utilisation d'une image système AOSP (qui n'aura pas non plus le nouveau composant système).

extensions d'image de fournisseur qui servent de nouveaux composants système

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

Semblable à l' exemple des extensions AOSP , la stratégie pour les interactions entre le système et le fournisseur doit être placée dans le répertoire device/ manufacturer / device-name /sepolicy fourni sur la partition du fournisseur (pour garantir que la stratégie système n'a aucune connaissance des détails spécifiques au fournisseur). Vous pouvez ajouter de nouveaux types publics qui étendent la stratégie dans system/sepolicy/public ; cela ne devrait être fait qu'en complément de la politique AOSP existante, c'est-à-dire ne pas supprimer la politique publique AOSP. Les nouveaux types publics peuvent ensuite être utilisés pour la stratégie dans system/sepolicy/private et dans device/ manufacturer / device-name /sepolicy .

Gardez à l'esprit 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 autres déclarations de stratégie ne sont pas pris en charge. De plus, les nouveaux types publics ne peuvent pas être utilisés pour étiqueter directement des objets dans la stratégie /vendor .

Scénarios de stratégie non pris en charge

Les appareils lancés avec Android 8.0 et versions ultérieures ne prennent pas en charge le scénario de stratégie et les exemples suivants.

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

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

Semblable à l’interaction du nouveau système (non-AOSP) et des composants du fournisseur , sauf que le nouveau type de système est introduit dans un OTA uniquement cadre. Bien que le nouveau type puisse être ajouté à la stratégie dans system/sepolicy/public , la stratégie du fournisseur existante n'a aucune connaissance du nouveau type car elle suit uniquement la politique 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 partenaire d'attribut ne sont pas prises en charge dans system/sepolicy/public , cette méthode n'est pas disponible pour la politique 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 manière dont il interagit avec un nouveau composant fournisseur non-AOSP.

La politique relative à l'image système doit être rédigée sans connaissance des personnalisations spécifiques du fournisseur. La politique concernant des interfaces spécifiques dans AOSP est ainsi exposée via des attributs dans system/sepolicy/public afin que la politique du fournisseur puisse adhérer à la future politique système qui utilise ces attributs. Cependant, les extensions d'attributs dans system/sepolicy/public ne sont pas prises en charge , donc toutes les politiques dictant la manière dont les composants du 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 AOSP system/sepolicy/public ) doivent être dans device/ manufacturer / device-name /sepolicy . Cela signifie que les types de systèmes ne peuvent pas modifier l'accès autorisé aux types de fournisseurs dans le cadre d'une OTA uniquement basée sur le framework.