Le processus d'initialisation dispose d'autorisations presque illimitées et utilise des scripts d'entrée provenant des partitions système et du fournisseur pour initialiser le système pendant le processus de démarrage. Cet accès crée un énorme trou dans la répartition système/fournisseur de Treble, car les scripts du fournisseur peuvent demander à init d'accéder à des fichiers, des propriétés, etc. qui ne font pas partie de l'interface binaire d'application (ABI) stable du système-fournisseur.
Vendor init est conçu pour combler cette faille en utilisant un domaine SELinux (Security-Enhanced Linux) vendor_init
distinct pour exécuter les commandes trouvées dans /vendor
avec des autorisations spécifiques au fournisseur.
Mécanisme
L'initialisation du fournisseur crée un sous-processus d'initialisation au début du processus de démarrage avec le contexte SELinux u:r:vendor_init:s0
. Ce contexte SELinux dispose d'autorisations considérablement moins nombreuses que le contexte init par défaut, et son accès est limité aux fichiers, propriétés, etc. qui sont spécifiques au fournisseur ou qui font partie de l'ABI stable du fournisseur.
Init vérifie chaque script qu'il charge pour voir si son chemin d'accès commence par /vendor
. Si c'est le cas, il le tague pour indiquer que ses commandes doivent être exécutées dans le contexte d'initialisation du fournisseur. Chaque commande intégrée init est annotée avec une valeur booléenne qui spécifie si la commande doit être exécutée ou non dans le sous-processus init du fournisseur:
- La plupart des commandes qui accèdent au système de fichiers sont annotées pour s'exécuter dans le sous-processus d'initialisation du fournisseur et sont donc soumises au SEPolicy d'initialisation du fournisseur.
- La plupart des commandes qui ont un impact sur l'état d'initialisation interne (par exemple, le démarrage et l'arrêt des services) sont exécutées dans le processus d'initialisation normal. Ces commandes sont informées qu'un script du fournisseur les appelle pour gérer ses propres autorisations non SELinux.
La boucle de traitement principale d'init contient une vérification qui, si une commande est annotée pour s'exécuter dans le sous-processus du fournisseur et provient d'un script du fournisseur, cette commande est envoyée via la communication inter-processus (IPC) au sous-processus d'initialisation du fournisseur, qui exécute la commande et renvoie le résultat à init.
Utiliser vendor init
L'initialisation du fournisseur est activée par défaut et ses restrictions s'appliquent à tous les scripts d'initialisation présents dans la partition /vendor
. L'initialisation du fournisseur doit être transparente pour les fournisseurs dont les scripts n'accèdent déjà pas aux fichiers, propriétés, etc. du système.
Toutefois, si les commandes d'un script de fournisseur donné ne respectent pas les restrictions d'initialisation du fournisseur, elles échouent. Une ligne correspondant à un échec s'affiche dans le journal du noyau (visible avec dmesg) à partir de l'initialisation. Un audit SELinux accompagne toute commande ayant échoué en raison de la règle SELinux. Exemple d'échec avec un audit SELinux:
type=1400 audit(1511821362.996:9): avc: denied { search } for pid=540 comm="init" name="nfc" dev="sda45" ino=1310721 scontext=u:r:vendor_init:s0 tcontext=u:object_r:nfc_data_file:s0 tclass=dir permissive=0 init: Command 'write /data/nfc/bad_file_access 1234' action=boot (/vendor/etc/init/hw/init.walleye.rc:422) took 2ms and failed: Unable to write to file '/data/nfc/bad_file_access': open() failed: Permission denied
Si une commande échoue, deux options s'offrent à vous:
- Si la commande échoue en raison d'une restriction prévue (par exemple, si elle accède à un fichier système ou à une propriété), elle doit être réimplémentée de manière compatible avec Treble, en passant par des interfaces stables uniquement. Les règles "Neverallow" empêchent d'ajouter des autorisations d'accès aux fichiers système qui ne font pas partie de l'ABI système-fournisseur stable.
- Si le libellé SELinux est nouveau et qu'il n'a pas encore reçu d'autorisations dans le
vendor_init.te
du système ni d'autorisations exclues via les règles neverallow, des autorisations peuvent être accordées au nouveau libellé dans levendor_init.te
spécifique à l'appareil.
Pour les appareils lancés avant Android 9, les règles "neverallows" peuvent être contournées en ajoutant l'attribut de type data_between_core_and_vendor_violators
au fichier vendor_init.te
spécifique à l'appareil.
Emplacements du code
La majeure partie de la logique de l'IPC d'initialisation du fournisseur se trouve dans system/core/init/subcontext.cpp.
Le tableau des commandes se trouve dans la classe BuiltinFunctionMap
dans system/core/init/builtins.cpp et inclut des annotations indiquant si la commande doit s'exécuter dans le sous-processus d'initialisation du fournisseur.
SEPolicy pour l'initialisation du fournisseur est réparti entre les répertoires privé (system/sepolicy/private/vendor_init.te) et public (system/sepolicy/public/vendor_init.te) de system/sepolicy.