Rosetta 2 sur un Mac avec puce Apple
Un Mac avec puce Apple est capable d’exécuter du code compilé pour le jeu d’instructions x86_64 au moyen du mécanisme de traduction Rosetta 2. Deux types de traduction sont offerts : à la volée et à l’avance.
Traduction à la volée
Dans le canal de traduction à la volée (JIT, Just in Time), un objet Mach x86_64 est rapidement identifié dans le chemin d’exécution des images. Lorsque ces images ont été trouvées, le noyau transfère le contrôle à une souche de traduction Rosetta spéciale plutôt qu’à l’éditeur de liens dynamiques, dyld(1)
. La souche de traduction traduit ensuite les pages x86_64 lors de l’exécution de l’image. Cette traduction se produit entièrement au sein du processus. Le noyau vérifie les hachages de code de chaque page x86_64 en les comparant à la signature du code jointe au fichier binaire, et ce, même en cas de défaut de page. Si un hachage ne correspond pas, le noyau applique la politique de correction appropriée pour ce processus.
Traduction à l’avance
Dans le chemin de traduction à l’avance (AOT, Ahead of Time), les fichiers binaires x86_64 sont lus à partir du stockage aux moments où la réactivité du code est considérée comme optimale par le système. Les artéfacts traduits sont écrits sur le stockage sous la forme d’un type spécial de fichier Mach-O. Ce fichier ressemble à une image exécutable, mais il est marqué de manière à indiquer qu’il s’agit du produit traduit d’une autre image.
Dans ce modèle, l’artéfact AOT extrait toutes les informations relatives à son identité de l’image exécutable x86_64 originale. Pour faire appliquer cette liaison, une entité de l’espace utilisateur privilégié signe l’artéfact de traduction au moyen d’une clé propre à l’appareil gérée par le Secure Enclave. Cette clé est remise uniquement à l’entité espace utilisateur privilégié, qui est identifiée comme telle au moyen d’un droit restreint. Le répertoire de code créé pour l’artéfact de traduction inclut le hachage du répertoire de code de l’image exécutable x86_64 originale. On appelle signature supplémentaire la signature apposée sur l’artéfact de traduction.
Le canal AOT commence de la même façon que le canal JIT, avec le noyau qui transfère le contrôle au moteur d’exécution de Rosetta plutôt qu’à l’éditeur de liens dynamiques, dyld(1)
. Mais le moteur d’exécution de Rosetta envoie ensuite une requête de communication interprocessus au service système Rosetta, qui demande si une traduction AOT est disponible pour l’image exécutable actuelle. S’il en trouve une, le service Rosetta fournit à cette traduction un descripteur qui sera mis en correspondance avec le processus et exécuté. Pendant l’exécution, le noyau fait appliquer les hachages de répertoire de code de l’artéfact de traduction, qui sont authentifiés par la signature associée à la clé de signature propre à l’appareil. Les hachages de répertoire de code de l’image x86_64 originale ne sont pas impliqués dans ce processus.
Les artéfacts traduits sont stockés dans un Data Vault qui pendant l’exécution n’est accessible par aucune autre entité que le service Rosetta. Le service Rosetta gère l’accès à son cache en distribuant des descripteurs de fichier en lecture seule à des artéfacts individuels de traduction. Cela limite l’accès au cache de l’artéfact AOT. La communication interprocessus de ce service et l’empreinte subordonnée sont intentionnellement limitées pour réduire la surface d’attaque.
Si le hachage du répertoire de code de l’image x86_64 originale ne correspond pas à celui encodé dans la signature de l’artéfact de traduction AOT, ce résultat est considéré comme équivalant à une signature de code non valide, et les actions d’app appropriées sont engagées.
Si un processus distant interroge le noyau au sujet des droits ou des autres propriétés d’identité du code d’un exécutable traduit en mode AOT, les propriétés d’identité de l’image x86_64 originale sont retournées.
Contenu du cache statique de confiance
macOS 11 ou une version ultérieure inclut des fichiers binaires Mach multiarchitectures qui contiennent des tranches de code informatique x86_64 et arm 64. Sur un Mac avec puce Apple, l’utilisateur peut décider d’exécuter la tranche x86_64 d’un fichier binaire système par l’intermédiaire de Rosetta (par exemple pour charger un module qui n’a aucune variante arm64 native). Pour ce faire, le cache statique de confiance compris dans macOS contient généralement trois hachages de répertoire de code par fichier Mach-O :
le hachage du répertoire de code de la tranche arm64;
le hachage du répertoire de code de la tranche x86_64;
le hachage du répertoire de code de la traduction AOT de la tranche x86_64.
La procédure de traduction AOT de Rosetta est déterministe, car elle reproduit la même sortie pour toute entrée donnée, et ce, indépendamment du moment ou de l’appareil où la traduction a eu lieu.
Pendant la construction de macOS, chaque fichier Mach-O passe par le canal de traduction AOT associé à la version de macOS en cours de construction, et le hachage de répertoire de code qui en résulte est enregistré dans le cache de confiance. Pour des raisons d’efficacité, les produits traduits ne sont pas inclus avec le système d’exploitation. Ils sont reconstitués sur demande quand l’utilisateur les requiert.
Lorsqu’une image x86_64 est exécutée sur un Mac avec puce Apple, si le hachage du répertoire de code de cette image se trouve dans le cache statique de confiance, le hachage du répertoire de code de l’artéfact AOT qui en résulte doit également s’y trouver. De tels produits ne sont pas signés par la clé propre à l’appareil, car l’autorité de signature est enracinée dans la chaîne de démarrage sécurisé d’Apple.
Code x86_64 non signé
Un Mac avec puce Apple n’autorise pas l’exécution d’un code arm64 natif sans signature valide. Cette signature peut être aussi simple qu’une signature de code « ad hoc » (cf. codesign(1)
) qui ne comporte aucune identité réelle dans la partie secrète d’une paire de clés asymétrique (il s’agit uniquement d’une mesure non vérifiée du fichier binaire).
Par souci de compatibilité avec le fichier binaire, le code x86_64 traduit peut s’exécuter par l’intermédiaire de Rosetta sans aucune information de signature. Aucune identité précise n’est transmise à ce code au moyen de la procédure de signature du Secure Enclave de l’appareil, et ce code s’exécute précisément avec les mêmes limites imposées au code non signé qui s’exécute sur un Mac avec processeur Intel.