Rosetta 2 en un Mac con chip de Apple
Un Mac con chip de Apple puede ejecutar código compilado para el conjunto de instrucciones de x86_64 mediante un mecanismo de traducción denominado Rosetta 2. Se ofrecen dos tipos de traducciones: en tiempo de ejecución y antes de la ejecución.
Traducción en tiempo de ejecución
En la canalización de traducción en tiempo de ejecución (JIT), el objeto Mach de x86_64 se identifica de forma temprana en la ruta de ejecución de la imagen. Cuando se encuentran estas imágenes, el kernel transfiere el control a un stub de traducción de Rosetta especial, en lugar de a un editor de enlaces dinámicos, dyld(1)
. A continuación, el stub de traducción traduce las páginas de x86_64 durante la ejecución de la imagen. Esta traducción se lleva a cabo completamente en el proceso. El kernel sigue verificando los hashes del código de cada página de x86_64 con la firma del código asociada al archivo binario. En el caso de que se detecte una discrepancia de hash, el kernel impone la política de corrección apropiada para ese proceso.
Traducción antes de la ejecución
En la ruta de traducción antes de la ejecución (AOT), se leen los archivos binarios de x86_64 del almacenamiento en los momentos en los que el sistema considera óptimos para la capacidad de respuesta de ese código. Los artefactos traducidos se escriben en el almacenamiento como un tipo especial de archivo de objeto Mach. Ese archivo es similar a una imagen ejecutable, pero está marcado para indicar que se trata del producto traducido de otra imagen.
En este modelo, el artefacto AOT obtiene toda su información de identidad de la imagen ejecutable x86_64 original. Para aplicar esta vinculación, una entidad del espacio del usuario con privilegios firma el artefacto de traducción mediante una clave específica del dispositivo que gestiona Secure Enclave. Esta clave solo se publica para la entidad del espacio del usuario con privilegios, que se identifica como tal mediante una autorización restringida. El directorio de código creado para el artefacto de traducción incluye el hash del directorio de código de la imagen ejecutable x86_64 original. La firma en el propio artefacto de traducción se denomina firma complementaria.
La canalización AOT comienza de manera similar a la canalización JIT, con el kernel que transfiere el control al tiempo de ejecución de Rosetta, en lugar de a un editor de enlaces dinámicos, dyld(1)
. Sin embargo, en este caso el tiempo de ejecución de Rosetta envía una consulta de comunicación entre procesos (IPC) al servicio del sistema Rosetta, que pregunta si hay disponible una traducción AOT para la imagen ejecutable actual. Si la hay, el servicio Rosetta proporciona un identificador a esa traducción, que se asigna al proceso y se ejecuta. Durante la ejecución, el kernel aplica los hashes del directorio de código del artefacto de traducción, que se autentican mediante la firma radicada en la clave de firma específica del dispositivo. Los hashes del directorio de código de la imagen x86_64 original no están implicados en el proceso.
Los artefactos traducidos se almacenan en un almacén seguro de datos que no es accesible en tiempo de ejecución por ninguna entidad, salvo el servicio Rosetta. El servicio Rosetta gestiona el acceso a su caché mediante la distribución de descriptores de archivos de solo lectura entre los artefactos de traducción individuales, lo que limita el acceso a la caché de artefactos AOT. De manera intencionada, se restringe considerablemente la comunicación entre procesos de este servicio y la huella dependiente para limitar la superficie de ataque.
Si el hash del directorio de código de la imagen x86_64 original no coincide con el codificado en la firma del artefacto de traducción AOT, este resultado se considera equivalente a una firma de código no válida, y se toma la medida coercitiva correspondiente.
Si un proceso remoto consulta al kernel las autorizaciones u otras propiedades de identidad de código de un ejecutable traducido antes del tiempo de ejecución (AOT), se le devolverán las propiedades de identidad de la imagen x86_64 original.
Contenido de la caché de confianza estática
macOS 11 o posterior incluye archivos binarios Mach que contienen fragmentos de código informático de arm64 y x86_64. En un Mac con chip de Apple, un usuario puede optar por ejecutar el fragmento de x86_64 de un archivo binario del sistema mediante la canalización de Rosetta; por ejemplo, para cargar un módulo que no tenga una variante de arm64 nativa. Para respaldar esto, por normal general, la caché de confianza estática incluida con macOS contiene tres hashes de directorio de código por cada archivo de objeto Mach.
Hash del directorio de código del fragmento de arm64
Hash del directorio de código del fragmento de x86_64
Hash del directorio de código de la traducción AOT del fragmento de x86_64
El procedimiento de traducción AOT de Rosetta es determinista, ya que reproduce resultados idénticos para cualquier entrada dada, independientemente de cuándo o en qué dispositivo se realizó la traducción.
Durante la compilación de macOS, cada archivo de objeto Mach se ejecuta mediante la canalización de traducción AOT de Rosetta asociada con la versión de macOS compilada, y el hash del directorio de código resultante se registra en la caché de confianza. Los propios productos traducidos no se incluyen con el sistema operativo por motivos de eficiencia y se vuelven a constituir a petición cuando el usuario los solicita.
Cuando se ejecuta una imagen x86_64 en un Mac con chip de Apple, si el hash del directorio de código de esa imagen está en la caché de confianza estática, también se espera que el hash del directorio de código del artefacto AOT resultante esté en la caché de confianza estática. Estos productos no están firmados por la clave específica del dispositivo, ya que la autoridad de firma está radicada en la cadena de arranque seguro de Apple.
Código de x86_64 no firmado
Un Mac con chip de Apple no permite que se ejecute código de arm64 nativo a menos que haya asociada una firma válida. Esta firma puede ser tan sencilla como una firma de código ad hoc (cf. codesign(1)
) que no contiene ninguna identidad de la mitad del secreto de un par de claves asimétricas (se trata simplemente de una medición no autenticada del archivo binario).
Para garantizar la compatibilidad con archivos binarios, se permite que se ejecute código de x86_64 traducido mediante Rosetta sin ninguna información de firma. No se transfiere ninguna identidad específica mediante el procedimiento de firma de Secure Enclave específico del dispositivo a este código, que se ejecuta exactamente con las mismas limitaciones que el código no firmado nativo que se ejecuta en un Mac basado en Intel.