Implémentation de SELinux

SELinux est configuré pour refuser par défaut, ce qui signifie que chaque accès pour lequel il dispose d'un hook dans le noyau doit être explicitement autorisé par la politique. Cela signifie qu'un fichier de stratégie comprend une grande quantité d'informations concernant les règles, les types, les classes, les autorisations, etc. Une considération complète de SELinux sort du cadre de ce document, mais comprendre comment écrire des règles de politique est désormais essentiel lors de la mise en place de nouveaux appareils Android. Il existe déjà de nombreuses informations disponibles concernant SELinux. Voir Documentation de support pour les ressources suggérées.

Fichiers clés

Pour activer SELinux, intégrez le dernier noyau Android puis incorporez les fichiers trouvés dans le répertoire system/sepolicy . Une fois compilés, ces fichiers comprennent la politique de sécurité du noyau SELinux et couvrent le système d'exploitation Android en amont.

En général, vous ne devez pas modifier directement les fichiers system/sepolicy . Au lieu de cela, ajoutez ou modifiez vos propres fichiers de stratégie spécifiques à l’appareil dans le répertoire /device/ manufacturer / device-name /sepolicy . Sous Android 8.0 et versions ultérieures, les modifications que vous apportez à ces fichiers ne devraient affecter que la stratégie de votre répertoire de fournisseurs. Pour plus de détails sur la séparation de la politique publique dans Android 8.0 et versions ultérieures, consultez Personnalisation de SEPolicy dans Android 8.0+ . Quelle que soit la version d'Android, vous modifiez toujours ces fichiers :

Fichiers de stratégie

Les fichiers qui se terminent par *.te sont des fichiers sources de politique SELinux, qui définissent les domaines et leurs étiquettes. Vous devrez peut-être créer de nouveaux fichiers de stratégie dans /device/ manufacturer / device-name /sepolicy , mais vous devriez essayer de mettre à jour les fichiers existants lorsque cela est possible.

Fichiers contextuels

Les fichiers de contexte sont l'endroit où vous spécifiez des étiquettes pour vos objets.

  • file_contexts attribue des étiquettes aux fichiers et est utilisé par divers composants de l'espace utilisateur. Lorsque vous créez de nouvelles stratégies, créez ou mettez à jour ce fichier pour attribuer de nouvelles étiquettes aux fichiers. Pour appliquer de nouveaux file_contexts , reconstruisez l'image du système de fichiers ou exécutez restorecon sur le fichier à réétiqueter. Lors des mises à niveau, les modifications apportées file_contexts sont automatiquement appliquées aux partitions système et de données utilisateur dans le cadre de la mise à niveau. Les modifications peuvent également être automatiquement appliquées lors de la mise à niveau vers d'autres partitions en ajoutant des appels restorecon_recursive à votre init. board .rc une fois la partition montée en lecture-écriture.
  • genfs_contexts attribue des étiquettes aux systèmes de fichiers, tels que proc ou vfat , qui ne prennent pas en charge les attributs étendus. Cette configuration est chargée dans le cadre de la politique du noyau, mais les modifications peuvent ne pas prendre effet pour les inodes internes, nécessitant un redémarrage ou un démontage et un remontage du système de fichiers pour appliquer pleinement la modification. Des étiquettes spécifiques peuvent également être attribuées à des montages spécifiques, tels que vfat à l'aide de l'option context=mount .
  • property_contexts attribue des étiquettes aux propriétés du système Android pour contrôler quels processus peuvent les définir. Cette configuration est lue par le processus init lors du démarrage.
  • service_contexts attribue des étiquettes aux services de classeur Android pour contrôler quels processus peuvent ajouter (enregistrer) et trouver (rechercher) une référence de classeur pour le service. Cette configuration est lue par le processus servicemanager lors du démarrage.
  • seapp_contexts attribue des étiquettes aux processus d'application et aux répertoires /data/data . Cette configuration est lue par le processus zygote à chaque lancement d'application et par installd au démarrage.
  • mac_permissions.xml attribue une balise seinfo aux applications en fonction de leur signature et éventuellement de leur nom de package. La balise seinfo peut ensuite être utilisée comme clé dans le fichier seapp_contexts pour attribuer une étiquette spécifique à toutes les applications avec cette balise seinfo . Cette configuration est lue par system_server lors du démarrage.
  • keystore2_key_contexts attribue des étiquettes aux espaces de noms Keystore 2.0. Ces espaces de noms sont appliqués par le démon keystore2. Keystore a toujours fourni des espaces de noms basés sur UID/AID. Keystore 2.0 applique en outre les espaces de noms définis par la stratégie de sécurité. Une description détaillée du format et des conventions de ce fichier peut être trouvée ici .

Makefile BoardConfig.mk

Après avoir modifié ou ajouté des fichiers de stratégie et de contexte, mettez à jour votre makefile /device/ manufacturer / device-name /BoardConfig.mk pour référencer le sous-répertoire sepolicy et chaque nouveau fichier de stratégie. Pour plus d'informations sur les variables BOARD_SEPOLICY , consultez le fichier system/sepolicy/README .

BOARD_SEPOLICY_DIRS += \
        <root>/device/manufacturer/device-name/sepolicy

BOARD_SEPOLICY_UNION += \
        genfs_contexts \
        file_contexts \
        sepolicy.te

Après la reconstruction, votre appareil est activé avec SELinux. Vous pouvez désormais soit personnaliser vos politiques SELinux pour prendre en compte vos propres ajouts au système d'exploitation Android, comme décrit dans Personnalisation , soit vérifier votre configuration existante comme indiqué dans Validation .

Lorsque les nouveaux fichiers de stratégie et les mises à jour BoardConfig.mk sont en place, les nouveaux paramètres de stratégie sont automatiquement intégrés dans le fichier de stratégie final du noyau. Pour plus d’informations sur la manière dont la stratégie de sécurité est créée sur l’appareil, consultez Création d’une stratégie de sécurité .

Mise en œuvre

Pour démarrer avec SELinux :

  1. Activez SELinux dans le noyau : CONFIG_SECURITY_SELINUX=y
  2. Modifiez le paramètre kernel_cmdline ou bootconfig de sorte que :
    BOARD_KERNEL_CMDLINE := androidboot.selinux=permissive
    ou
    BOARD_BOOTCONFIG := androidboot.selinux=permissive
    Ceci est uniquement destiné au développement initial de la stratégie pour le périphérique. Une fois que vous avez défini une politique d'amorçage initiale, supprimez ce paramètre afin que votre appareil l'applique, sinon il échouera au CTS.
  3. Démarrez le système en mode permissif et voyez quels refus sont rencontrés au démarrage :
    Sur Ubuntu 14.04 ou version ultérieure :
    adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/BOARD/root/sepolicy
    
    Sur Ubuntu 12.04 :
    adb pull /sys/fs/selinux/policy
    adb logcat -b all | audit2allow -p policy
    
  4. Évaluez le résultat pour les avertissements qui ressemblent init: Warning! Service name needs a SELinux domain defined; please fix! Voir Validation pour les instructions et les outils.
  5. Identifiez les appareils et autres nouveaux fichiers nécessitant un étiquetage.
  6. Utilisez des étiquettes existantes ou nouvelles pour vos objets. Examinez les fichiers *_contexts pour voir comment les choses étaient auparavant étiquetées et utilisez la connaissance de la signification des étiquettes pour en attribuer une nouvelle. Idéalement, il s'agira d'un label existant qui s'intégrera dans la politique, mais parfois un nouveau label sera nécessaire, ainsi que des règles d'accès à ce label. Ajoutez vos étiquettes aux fichiers contextuels appropriés.
  7. Identifiez les domaines/processus qui doivent avoir leurs propres domaines de sécurité. Vous devrez probablement rédiger une toute nouvelle politique pour chacun. Tous les services générés par init , par exemple, devraient avoir le leur. Les commandes suivantes permettent de révéler celles qui restent en cours d'exécution (mais TOUS les services nécessitent un tel traitement) :
    adb shell su -c ps -Z | grep init
    
    adb shell su -c dmesg | grep 'avc: '
    
  8. Vérifiez init. device .rc pour identifier tous les domaines qui n'ont pas de type de domaine. Donnez-leur un domaine au début de votre processus de développement pour éviter d'ajouter des règles à init ou de confondre les accès init avec ceux qui figurent dans leur propre politique.
  9. Configurez BOARD_CONFIG.mk pour utiliser les variables BOARD_SEPOLICY_* . Voir le README dans system/sepolicy pour plus de détails sur cette configuration.
  10. Examinez le fichier init. device .rc et fstab. device et assurez-vous que chaque utilisation de mount correspond à un système de fichiers correctement étiqueté ou qu'une option context= mount est spécifiée.
  11. Parcourez chaque refus et créez une politique SELinux pour gérer chacun correctement. Voir les exemples dans Personnalisation .

Vous devez commencer par les politiques de l’AOSP, puis vous en inspirer pour vos propres personnalisations. Pour plus d'informations sur la stratégie politique et un examen plus approfondi de certaines de ces étapes, consultez Écriture d'une politique SELinux .

Cas d'utilisation

Voici des exemples spécifiques d'exploits à prendre en compte lors de la création de votre propre logiciel et des politiques SELinux associées :

Liens symboliques : les liens symboliques apparaissant sous forme de fichiers, ils sont souvent lus comme des fichiers, ce qui peut conduire à des exploits. Par exemple, certains composants privilégiés, comme init , modifient les autorisations de certains fichiers, parfois pour les rendre excessivement ouverts.

Les attaquants pourraient alors remplacer ces fichiers par des liens symboliques vers le code qu'ils contrôlent, permettant ainsi à l'attaquant d'écraser des fichiers arbitraires. Mais si vous savez que votre application ne traversera jamais un lien symbolique, vous pouvez lui interdire de le faire avec SELinux.

Fichiers système - Considérez la classe de fichiers système qui doit être modifié uniquement par le serveur système. Néanmoins, puisque netd , init et vold s'exécutent en tant que root, ils peuvent accéder à ces fichiers système. Ainsi, si netd était compromis, cela pourrait compromettre ces fichiers et potentiellement le serveur système lui-même.

Avec SELinux, vous pouvez identifier ces fichiers en tant que fichiers de données du serveur système. Par conséquent, le seul domaine qui y a accès en lecture/écriture est le serveur système. Même si netd était compromis, il ne pourrait pas basculer de domaine vers le domaine du serveur système et accéder à ces fichiers système bien qu'il s'exécute en tant que root.

Données d'application - Un autre exemple est la classe de fonctions qui doivent s'exécuter en tant que root mais ne doivent pas accéder aux données d'application. Ceci est incroyablement utile car des affirmations très diverses peuvent être faites, telles que l'interdiction de certains domaines sans rapport avec les données d'application d'accéder à Internet.

setattr - Pour les commandes telles que chmod et chown , vous pouvez identifier l'ensemble de fichiers dans lesquels le domaine associé peut exécuter setattr . Tout ce qui est en dehors de cela pourrait être interdit dans ces modifications, même par root. Ainsi, une application peut exécuter chmod et chown sur ceux étiquetés app_data_files mais pas shell_data_files ou system_data_files .