Le processus init dispose d'autorisations presque illimitées et utilise des scripts d'entrée des partitions système et fournisseur pour initialiser le système pendant le processus de démarrage. Cet accès crée un énorme trou dans la séparation Treble entre le système et le fournisseur, 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 et du fournisseur.
Vendor init est conçu pour combler cette lacune en utilisant un domaine Security-Enhanced Linux (SELinux) distinct vendor_init
pour exécuter les commandes trouvées dans /vendor
avec des autorisations spécifiques au fournisseur.
Mécanisme
Vendor init crée un sous-processus d'init au début du processus de démarrage avec le contexte SELinux u:r:vendor_init:s0
. Ce contexte SELinux dispose de beaucoup moins d'autorisations 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 du système.
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 marque pour indiquer que ses commandes doivent être exécutées dans le contexte d'initialisation du fournisseur. Chaque init intégré est annoté avec un booléen 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 init du fournisseur et sont donc soumises à la SEPolicy init 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 de fournisseur les appelle pour gérer leurs 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 interprocessus (IPC) au sous-processus init 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 uniquement.
Toutefois, si les commandes d'un script de fournisseur donné enfreignent les restrictions d'initialisation du fournisseur, elles échouent. Les commandes qui échouent comportent une ligne dans le journal du noyau (visible avec dmesg) à partir de l'init indiquant l'échec. Un audit SELinux accompagne toute commande ayant échoué en raison de la règle SELinux. Exemple d'échec incluant 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 la commande accède à un fichier ou à une propriété système), elle doit être réimplémentée de manière compatible avec Treble, en passant uniquement par des interfaces stables. Les règles "neverallow" empêchent l'ajout d'autorisations d'accès aux fichiers système qui ne font pas partie de l'ABI stable du fournisseur du système.
- Si le libellé SELinux est nouveau et n'a pas déjà reçu d'autorisations dans le
vendor_init.te
du système ni d'autorisations exclues par les règles neverallow, le nouveau libellé peut recevoir des autorisations dans levendor_init.te
spécifique à l'appareil.
Pour les appareils lancés avant Android 9, les règles neverallow 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 de 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
de system/core/init/builtins.cpp et inclut des annotations qui indiquent si la commande doit s'exécuter dans le sous-processus init du fournisseur.
La SEPolicy pour l'initialisation du fournisseur est divisée entre les répertoires privés (system/sepolicy/private/vendor_init.te) et publics (system/sepolicy/public/vendor_init.te) dans system/sepolicy.