Rosetta 2 auf Mac-Computern mit Apple Chips
Mac-Computer mit Apple Chips können Code ausführen, der für den x86_64 Befehlssatz (Instruction Set) kompiliert wurde. Dafür nutzen sie einen Übersetzungsmechanismus namens Rosetta 2. Es stehen zwei Übersetzungsarten zur Verfügung: Just-in-time und Ahead-of-time.
Just-in-time-Übersetzung
Bei der Just-in-time (JIT)-Übersetzungspipeline wird ein x86_64 Mach-Objekt in einer frühen Ausführungsphase der Image-Datei erkannt. Wird es erkannt, übergibt der Kernel die Steuerung an einen speziellen Rosetta Übersetzungs-Stub anstatt an den dynamischen Link-Editor dyld(1)
. Dieser Stub übersetzt x86_64-Seiten während der Ausführung der Image-Datei. Dieser Übersetzungsvorgang vollzieht sich vollständig innerhalb des Prozesses. Der Kernel verifiziert weiterhin die Code-Hashes aller x86_64-Seiten, indem er sie mit der Codesignatur abgleicht, die mit der Binärdatei verknüpft ist. Wenn die Hash-Werte nicht übereinstimmen, erzwingt der Kernel die für diesen Prozess geeignete Wiederherstellungsrichtlinie.
Ahead-of-time-Übersetzung
Bei der Ahead-of-time (AOT)-Übersetzung, werden x86_x64-Binärdateien zu den Zeitpunkten aus dem Speicher ausgelesen, die das System als optimal für die Reaktionsschnelligkeit dieses Codes beurteilt. Die übersetzten Artefakte werden als spezielle Mach-Objektdateien in den Speicher geschrieben. Diese Datei ist einer ausführbaren Image-Datei ähnlich, aber sie ist markiert, sodass angezeigt wird, dass sie das übersetzte Produkt einer anderen Image-Datei ist.
Bei diesem Modell bezieht das AOT-Artefakt alle Informationen über seine Identität aus der ursprünglichen ausführbaren x86_x64-Image-Datei. Um diese Bindung durchzusetzen, signiert eine privilegierte Entität im Benutzerbereich das Übersetzungsartefakt mit einem gerätespezifischen Schlüssel, der von der Secure Enclave verwaltet wird. Dieser Schlüssel wird nur der privilegierten Entität im Benutzerbereich zur Verfügung gestellt, die mit einer eingeschränkten Berechtigung als solche identifiziert wird. Das Codeverzeichnis, das für das Übersetzungsartefakt erstellt wird, enthält den Codeverzeichnis-Hash der ursprünglichen ausführbaren x86_x64-Image-Datei. Die Signatur des Übersetzungsartefakts selber wird als Ergänzungssignatur bezeichnet.
Die AOT-Pipeline startet ähnlich wie die JIT-Pipeline: Der Kernel übergibt die Steuerung an die Rosetta-Laufzeit anstatt an den dynamischen Link-Editor dyld(1)
. Anschließend sendet die Rosetta-Laufzeit eine IPC-Anfrage (Interprocess Communication) an den Rosetta-Systemservice. Dieser fragt ab, ob eine AOT-Übersetzung für die aktuelle ausführbare Image-Datei verfügbar ist. Wird eine solche gefunden, stellt der Rosetta-Dienst ein Handle für diese Übersetzung bereit, wonach sie in den Prozess gemappt und ausgeführt wird. Während der Ausführung erzwingt der Kernel die Codeverzeichnis-Hashes des Übersetzungsartefakts, welches durch die Signatur authentifiziert wird, die im gerätespezifischen Signierungsschlüssel hinterlegt ist. Die Codeverzeichnis-Hashes der ursprünglichen x86_x64-Image-Datei sind nicht an diesem Prozess beteiligt.
Übersetzte Artefakte werden im Data Vault gespeichert, auf den keine andere Entität außer dem Rosetta-Dienst Laufzeitzugriff erhält. Der Rosetta-Dienst verwaltet den Zugriff auf seinen Cache, indem er schreibgeschützte Dateideskriptoren an einzelne Übersetzungsartefakte verteilt. Auf diese Weise wird der Zugriff auf den AOT-Artefakt-Cache eingeschränkt. Der IPC dieses Diensts und sein Footprint sind absichtlich sehr begrenzt, um die Angriffsoberfläche klein zu halten.
Stimmt der Codeverzeichnis-Hash der ursprünglichen x86_x64-Image-Datei nicht mit demjenigen überein, der in die Signatur des AOT-Übersetzungsartefakt kodiert ist, wird dies als gleichbedeutend mit einer ungültigen Codesignatur angesehen; in diesem Fall werden entsprechende Durchsetzungsmaßnahmen ergriffen.
Fragt ein Remote-Prozess die Berechtigungen oder andere Identitätseigenschaften einer ausführbaren AOT-Übersetzung beim Kernel ab, werden die Identitätseigenschaften der ursprünglichen x86_x64-Image-Datei ausgegeben.
Inhalte des statischen Cache für die Vertrauensstellung (Static Trust Cache)
macOS 11 (oder neuer) wird mit „fat“ Mach-Binärdateien ausgeliefert, die Slices des x86_X64- und des arm64-Computercodes enthalten. Benutzer können das x86_x64-Slice einer Systemdatei auf einem Mac mit Apple Chips mit der Rosetta-Pipeline ausführen; z. B. um ein Plug-In zu laden, für das keine native arm64-Variante existiert. Um diesen Ansatz zu unterstützen, enthält der Static Trust Cache, der mit macOS ausgeliefert wird, allgemein drei Codeverzeichnis-Hashes pro Mach-Objektdatei:
Codeverzeichnis-Hash des arm64-Slice
Codeverzeichnis-Hash des x86_64-Slice
Codeverzeichnis-Hash der AOT-Übersetzung des x86_64-Slice
Der AOT-Übersetzungsprozess von Rosetta ist deterministisch und reproduziert die gleiche Ausgabe für jede Eingabe – unabhängig davon, wann oder auf welchem Gerät die Übersetzung durchgeführt wurde.
Während der Erstellung von macOS wird jedes Mach-Objekt durch die AOT-Übersetzungspipeline von Rosetta geleitet, die mit der jeweiligen Version von macOS verknüpft ist. Der daraus resultierende Codeverzeichnis-Hash wird im Trust Cache erfasst. Die übersetzten Produkte selbst sind aus Effizienzgründen nicht im Betriebssystem enthalten und können auf Anfrage des Benutzers neu erstellt werden.
Wenn eine x86_x64-Image-Datei auf einem Mac mit Apple Chips ausgeführt wird und sich der Codeverzeichnis-Hash dieser Image-Datei im statischen Trust Cache befindet, wird erwartet, dass sich der Codeverzeichnis-Hash des resultierenden AOT-Artefakts ebenfalls im statischen Trust Cache befindet. Solche Produkte werden nicht mit dem gerätespezifischen Schlüssel signiert, da die Signierungsautorität im sicheren Startvorgang verankert ist.
Nicht signierter x86_x64-Code
Mac-Computer mit Apple Chips erlauben keine Ausführung von nativem arm64-Code ohne verknüpfte Codesignatur. Dabei kann es sich um eine ganz einfache Ad-hoc-Codesignatur (vgl. codesign(1)
) handeln, die keinen Teil der Identität der geheimen Hälfte eines asymmetrischen Schlüsselpaars aufweist. (Bei ihr handelt es sich einfach um eine unauthentifizierte Kennzahl der Binärdatei.)
Übersetzter x86_x64-Code darf dagegen aus Gründen der Binärkompatibilität ohne jegliche Signaturinformationen mit Rosetta ausgeführt werden. Diesem Code wird keine spezifische Identität durch den gerätespezifischen Signierungsprozess der Secure Enclave offengelegt. Er wird mit genau denselben Einschränkungen ausgeführt wie ein nativer unsignierter Code auf einem Intel-basierten Mac.