
Sicherheitslücke in der Hypervisor-Firmware einiger älterer Qualcomm-Chipsätze
CVE-2022-22063 ist ein Sicherheitsproblem in der Hypervisor-Firmware einiger älterer Qualcomm-Chipsätze. Eine ungeschützte Hardware-Komponente (der „Boot-Remapper“) kann missbraucht werden, um von einem modifizierten Betriebssystem aus vollen Lese-/Schreibzugriff auf den Hypervisor zu erlangen (Privilege Escalation). Die Ausnutzung des Problems ist auf betroffenen Plattformen trivial, da keine Kenntnisse über die spezifische Firmware-Version (z. B. Adressen oder Variablen) erforderlich sind.
Hinweis: Obwohl Qualcomm Kunden Fixes bereitgestellt hat (mit reichlich Zeit, Updates zu veröffentlichen), sind viele betroffene Geräte bereits recht alt und erhalten den Fix vom Hersteller möglicherweise nicht. Das Problem kann nur von einem modifizierten oder kompromittierten Betriebssystem aus ausgenutzt werden (unter Verwendung eines anderen Sicherheitsproblems). Das Betriebssystem aktuell und sicher zu halten, könnte ausreichend sein, selbst wenn die Firmware verwundbar ist.
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HDas Problem wurde auch in [Qualcomms Sicherheitsbulletin vom Dezember 2022] veröffentlicht.
Das Problem hängt von einer Kombination aus Hardware und Software ab, die auf dem betroffenen Zielgerät läuft:
hyp-Partition im internen Speicher).APCS_BOOT_START_ADDR_NSEC), die nicht vom Hypervisor geschützt wird und daher für den weniger privilegierten Betriebssystem-Kernel (z. B. Linux) zugänglich ist.Es gibt mehrere weitere Chipsätze, die wahrscheinlich die betroffene Hardware haben (z. B. MSM8909 und MSM8953), aber sie besitzen keine separate Hypervisor-Firmware, die kompromittiert werden könnte.
Privilege Escalation: Bei einem bereits kompromittierten Betriebssystem-Kernel (z. B. Linux) ermöglicht das Problem, Privilegien trivial auf die Hypervisor-Ebene anzuheben (EL1 -> EL2 auf ARM). Der gesamte vom Hypervisor verwaltete Speicher kann gelesen oder beschrieben werden. Dadurch wird die Isolation verschiedener Sicherheitsdomänen oder virtueller Maschinen, die vom Hypervisor verwaltet werden (sofern vorhanden, je nach Konfiguration), aufgehoben.
(Siehe auch: Eine Einführung in die Zugriffskontrolle auf Qualcomm-Snapdragon-Plattformen)
Secure Boot: Die meisten in der Produktion erhältlichen Qualcomm-Geräte verwenden Secure Boot, um unbefugte Änderungen an der Firmware zu verhindern. Die Firmware wird kryptografisch signiert und von der Boot-Kette verifiziert. Das Problem ermöglicht es, die geladene Hypervisor-Firmware zur Laufzeit von einem modifizierten Betriebssystem aus zu ändern oder sogar vollständig zu ersetzen (entweder über offiziell unterstütztes „Bootloader-Unlocking“ oder einen anderen Exploit).
(Siehe auch: [Qualcomm Secure Boot and Image Authentication Technical Overview (v1.0)] und (v2.0))
Hinweis: Das Problem wurde ursprünglich auf der Plattform Qualcomm Snapdragon 410 (MSM8916) gefunden. Einige der folgenden Erklärungen könnten spezifisch für MSM8916 sein, z. B.:
Das allgemeine Konzept gilt jedoch in ähnlicher Weise für alle betroffenen Plattformen.
Die 64-Bit-ARMv8-A-Architektur definiert 4 Privilegienstufen („Exception Levels“, EL). Es gibt getrennte Ebenen, die typischerweise für Anwendungen, Betriebssystem-Kernel und einen Hypervisor verwendet werden:
Die CPU wechselt während Exceptions zwischen den Ebenen, z. B. aufgrund eines eingehenden Interrupts. Es ist auch möglich, mit speziellen Befehlen wie dem Hypervisor Call (hvc) zwischen einigen Ebenen zu wechseln.
(Siehe auch: [AArch64-Exception-Modell])
Der Hypervisor kann eine oder mehrere virtuelle Maschinen mit separaten Betriebssystem-Kerneln hosten. Jede virtuelle Maschine kann mithilfe der Stage-2-Übersetzung eine eigene Sicht auf den Speicher erhalten. Alle Speicherzugriffe einer virtuellen Maschine durchlaufen zwei Übersetzungsstufen: Die erste wird vom (virtuellen) Betriebssystem verwaltet, während die zweite Stufe vom Hypervisor verwaltet wird. Vom Hypervisor oder von anderen virtuellen Maschinen genutzter Speicher kann ausgeblendet werden, indem er aus den Übersetzungstabellen ausgelassen wird.
(Siehe auch: AArch64-Virtualisierung, AArch64-Speicherverwaltung)
Qualcomms Hypervisor-Firmware läuft in EL2 und verwendet die Stage-2-Übersetzung, um Zugriff auf den Hypervisor-Speicher vom Haupt-Betriebssystem-Kernel in EL1 (normalerweise Linux) zu verhindern. Beachten Sie, dass die Stage-2-Übersetzung in diesem Aufbau hauptsächlich zum Speicherschutz ohne Adressübersetzung verwendet wird. Das Haupt-Betriebssystem hat direkten Zugriff auf die meisten Hardware-Komponenten im Memory-Mapped-Input/Output-Bereich (MMIO), z. B. den SD-Controller oder das Kamera-Subsystem. Zugriff auf Speicher, der zum Hypervisor/EL2 (hyp) und zum Secure Monitor/EL3 (Teil von tz) gehört, ist eingeschränkt:
Der Boot-Remapper hat nichts mit Virtualisierung zu tun: Er wird beim frühen Boot eines CPU-Kerns benötigt. Auf dieser Hardware-Plattform beginnen die CPU-Kerne die Ausführung immer an Adresse 0x0. Der Boot-Remapper ist eine zusätzliche Hardware-Komponente, die um die CPU herum aufgebaut ist und die ersten 64 oder 128 KiB (0x00000 - 0x20000) auf einen konfigurierbaren Speicherbereich umsetzt.
Standardmäßig zeigt der Boot-Remapper auf das Boot-ROM (den ersten Code, der beim Start des Geräts ausgeführt wird). Später wird die Zuordnung geändert, sodass die anderen CPU-Kerne sofort mit der Ausführung in der EL3-Firmware (Teil von tz) beginnen, die in den RAM geladen wurde:
Beachten Sie, wie die vom CPU angesprochene Adresse (innerhalb von tz) über zwei verschiedene physische Adressen erreichbar ist: die echte Adresse im RAM (0x8650xxxx) und die umgesetzte Adresse über den Boot-Remapper (0x0000xxxx).
Es gibt tatsächlich zwei separate Instanzen des Boot-Remappers:
APCS_BOOT_START_ADDR_SEC (= 0x0b010004) konfigurierbar, jedoch nur im sicheren Zustand.APCS_BOOT_START_ADDR_NSEC (= 0x0b010008) konfigurierbar, sogar im nicht-sicheren Zustand.Beide Boot-Remapper-Instanzen können über ein Speicherregister konfiguriert werden, das die Basisadresse für den umgesetzten Bereich sowie zwei Konfigurationsbits enthält: REMAP_EN zum Aktivieren der Umsetzung und BOOT_128KB_EN, um die ersten 128 KiB statt nur 64 KiB umzusetzen.
(Siehe auch: [Qualcomm Snapdragon 410E Technical Reference Manual rev. D], Seiten 85 und 116)
Mit dem Wissen aus den beiden vorherigen Abschnitten ist die Grundidee einfach: Nutzen Sie den Boot-Remapper, um den Speicherschutz (Stage-2-Übersetzung) des Hypervisors zu umgehen.
Der Boot-Remapper funktioniert nicht nur beim CPU-Start. Er kann jederzeit verwendet werden und erlaubt vollen Lese-/Schreib-/Ausführungszugriff auf den umgesetzten Bereich. Außerdem scheint Qualcomms Hypervisor das Betriebssystem auf betroffenen Geräten nicht daran zu hindern, die Non-secure-Instanz des Boot-Remappers zu konfigurieren und darauf zuzugreifen (sie ist nicht durch die Stage-2-Übersetzung geschützt). Daher ist das Problem leicht auszunutzen, indem man:
hyp, die an Adresse 0x8640xxxx beginnt), und dannDie umgesetzte Region kann dynamisch (Block für Block) verschoben werden, um auf Speicherbereiche zuzugreifen, die größer sind als die über den Boot-Remapper verfügbaren 64/128 KiB. Es ist auch möglich, damit den Hypervisor-Speicherschutz vollständig zu deaktivieren (siehe Proof of Concept).
Hinweis: Der gleiche Exploit funktioniert nicht für die Secure-World-Firmware (tz). Während der Boot-Remapper das Umgehen der Stage-2-Übersetzung ermöglicht, scheint der tz-Speicherbereich im DRAM durch eine zusätzliche Hardware-Komponente (außerhalb der CPU) geschützt zu sein, die den Zugriff blockiert, nachdem er den Boot-Remapper passiert hat:
Die tz-Speicherregion ist wahrscheinlich nur im sicheren Zustand zugänglich. Der Exploit erlaubt nur, den Speicherschutz des Hypervisors zu umgehen; andere Sicherheitsmechanismen der Hardware bleiben bestehen.
Der Boot-Remapper kann verwendet werden, um die ursprüngliche Hypervisor-Firmware zur Laufzeit vollständig zu deaktivieren und zu ersetzen, ohne Kenntnis der Firmware-Version. Insbesondere ist es nicht erforderlich, Reverse Engineering zu betreiben, um Speicheradressen von Variablen und Funktionen zu ermitteln, die geändert werden könnten. Es reicht, die ungefähre Speicherregion der Hypervisor-Firmware zu kennen, z. B. aus der Speicherreservierung im Open-Source-Linux-Code oder durch Lesen der ELF-Header der Hypervisor-Firmware-Binärdatei (verfügbar in der hyp-Partition im internen Speicher).
Die allgemeine Idee ist:
hvc) ausführen, um vom Betriebssystem in den Hypervisor zu wechseln (von EL1 zu EL2).Der Code, der dies implementiert, ist nicht lang, beinhaltet jedoch etwas Low-Level-AArch64-Assembly und sorgfältige Interaktion mit den CPU-Caches. Die Hauptfrage bleibt jedoch offen: Wo genau sollte der Shellcode geschrieben werden, ohne den Code für eine bestimmte Hypervisor-Firmware-Version spezifisch zu machen?
Während eines Hypervisor Calls (oder allgemein einer Exception) wird die CPU-Ausführung auf eine spezielle Speicheradresse gezwungen: den Exception Vector. Die Exception Vectors sind Teil einer größeren Vector Table, die den Code enthält, der verschiedene Arten von Exceptions behandelt, die von der aktuellen oder niedrigeren Exception-Ebenen stammen:
Jedes Kästchen stellt einen Exception Vector mit Platz für 32 Assembler-Befehle dar. Dies ist nicht genug Platz, daher enthalten sie normalerweise Sprungbefehle, die zu einer anderen Stelle mit mehr Platz für zusätzlichen Code springen.
Die Offsets sind relativ zum Vector Base Address Register (VBAR), das die Basisadresse der Vector Table für jede Exception-Ebene definiert. Der Hypervisor schreibt die Basisadresse in das CPU-Register VBAR_EL2.
Ein Hypervisor Call ist eine synchrone Exception, die von einer niedrigeren Exception-Ebene ausgelöst wird (vom Betriebssystem-Kernel in EL1 zum Hypervisor in EL2). Wenn der Betriebssystem-Kernel im 32-Bit-Modus läuft, springt die CPU daher zu VBAR_EL2+0x600, oder im 64-Bit-Modus zu VBAR_EL2+0x400. Nachdem der Boot-Remapper verwendet wurde, um eigenen Code an diese Adresse zu schreiben, und ein Hypervisor Call ausgeführt wird, würde die CPU mit der Ausführung des Shellcodes beginnen.
Leider ist VBAR_EL2 für den Betriebssystem-Kernel in EL1 nicht lesbar. Es ist nur vom Hypervisor (EL2) selbst oder höher lesbar. Dennoch erleichtert dieses Wissen das Erraten der Einstiegsadresse per Brute Force erheblich: Die Basisadresse der Vector Table muss an ihrer Größe (0x800 = 2 KiB) ausgerichtet sein (ein Vielfaches davon). Das bedeutet, es gibt nur 64 mögliche Positionen innerhalb einer Region von 128 KiB, oder 512 innerhalb einer Region von 1 MiB:
Die roten Kästchen zeigen alle möglichen Positionen, an die die CPU während des Hypervisor Calls springen könnte. Den Shellcode an alle diese Positionen zu schreiben, reicht aus, um den Ansatz unabhängig von einer bestimmten Firmware-Version zu halten (die die Vector Table tatsächlich an einer bestimmten Adresse haben wird).
Dies könnte weiter verbessert werden: Der Boot-Remapper erlaubt sowohl Lese- als auch Schreibzugriff, sodass es möglich wäre, einige Heuristiken auf Basis des vorhandenen Codes und der Daten, die aus den Speicherpositionen gelesen werden, hinzuzufügen. Er sollte gültige AArch64-Instruktionen (A64) und wahrscheinlich einige wiederholte Füllbytes wie NOPs oder Sprungbefehle enthalten. (Der Platz für die 32 Instruktionen pro Exception Vector ist oft nur teilweise genutzt, da es einfacher ist, zu einer richtigen Funktion mit mehr Platz zu springen.)
Der in diesem Repository enthaltene Proof-of-Concept-Code ist eine Modifikation des Open-Source-Bootloaders Little Kernel (LK) von Qualcomm für die Plattform Snapdragon 410 (MSM8916/APQ8016), ursprünglich gedacht zum Testen mit dem DragonBoard-410c-Entwicklungsboard. All dies wurde der Einfachheit halber gewählt; das Problem kann auch von anderen Betriebssystemen (wie Linux), anderen betroffenen Plattformen und sogar Geräten mit Secure Boot ausgenutzt werden – solange es eine Möglichkeit gibt, eigenen Code im Betriebssystem-Kernel auszuführen.
Der Code implementiert den oben beschriebenen Ansatz, um den laufenden Hypervisor vollständig zu deaktivieren und anschließend durch eine andere Version zu ersetzen. Der neue „Hypervisor“ unterstützt keine virtuellen Maschinen, ist aber in der Lage, die Antwort auf die ultimative Frage nach dem Leben, dem Universum und allem mithilfe eines einfachen Hypervisor Calls zu geben:``` $ fastboot oem CVE-2022-22063 < waiting for any device > (bootloader) Hypervisor, what is the Answer to The Ultimate Question of (bootloader) Life, the Universe and Everything? (bootloader) Old hypervisor returned answer: -2 (bootloader) Old non-secure boot remapper base address: 0x100000 (bootloader) Setting boot remapper to hypervisor memory (0x86400000) (bootloader) Using boot remapper to copy shell code to hypervisor memory (bootloader) Copying to all possible vector tables (starting at 0x600) (bootloader) Calling shell code to disable running hypervisor (bootloader) Found old EL2 vector base address at 0x86404000 (bootloader) Copying new code directly to hypervisor memory (0x86400000) (bootloader) Hypervisor, what is the Answer to The Ultimate Question of (bootloader) Life, the Universe and Everything? (bootloader) New hypervisor returned answer: 42 OKAY [ 0.015s] Finished. Total time: 0.015s
### Testen
Der Proof-of-Concept-Code kann wie folgt erstellt und getestet werden:```shell
$ git clone https://git.codelinaro.org/clo/la/kernel/lk.git -b caf_migration/LA.BR.1.2.9.1_rb1.5
$ cp CVE-2022-22063.c lk/platform/msm8916/
$ git apply LK.diff
# Build LK for msm8916 and flash it to device
$ fastboot oem CVE-2022-22063
...
Allerdings ist diese Konfiguration nur für das DragonBoard-410c-Entwicklungsboard und andere Geräte ohne Secure Boot geeignet, bei denen der primäre Bootloader einfach (und sicher) ersetzt werden kann. Der Code in diesem Repository dient hauptsächlich als Referenz und nicht zur einfachen Verwendung/Testung.
In Zukunft ist geplant, den Code in eine neue Version von lk2nd zu integrieren, die auf verschiedenen Geräten viel einfacher getestet werden kann, ohne den primären Bootloader zu ersetzen.
Laut Qualcomm wurde das Problem behoben, indem der Zugriff auf die Boot-Remapper-Region mithilfe der Stage-2-Übersetzung untersagt wurde. Die Boot-Remapper-Konfiguration (APCS_BOOT_START_ADDR_NSEC-Register) ist weiterhin zugänglich, aber jetzt sind beide Speicherregionen blockiert:
Ein weiterer möglicher Fix wäre, das Register APCS_BOOT_START_ADDR_NSEC im Hypervisor zu schützen. Die umgemappte Region könnte in diesem Fall weiterhin zugänglich bleiben, da das Betriebssystem keine Möglichkeit hätte, den Boot-Remapper auf andere Speicherregionen umzukonfigurieren.
Laut Qualcomm war das Problem besonders schwer zu behandeln, da ihre üblichen Automatisierungswerkzeuge nicht verwendet werden konnten. Die meisten Probleme, die sie erhalten, sind Softwareprobleme, bei denen betroffene Geräte durch Prüfen des Quellcodes identifiziert werden können. Für dieses Problem war es erforderlich, sowohl Hardware als auch Software manuell zu prüfen (ob die Plattform das problematische Register besitzt und ob der Hypervisor verwundbar ist). Leider bedeutete der Verzicht auf die Automatisierung auch, dass das Problem nicht automatisch in einem Sicherheitsbulletin eingeplant wurde. Die zweite Verlängerung des Embargos wurde angefordert, um Kunden auf das Sicherheitsproblem aufmerksam zu machen und ihnen Zeit zu geben, ihre Geräte zu patchen. Sie arbeiten daran, den Prozess zu verbessern, um solche Probleme bei zukünftigen Meldungen zu vermeiden.
CVE-2022-22063 Bericht und Diagramme © 2022 von Stephan Gerhold sind lizenziert unter Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0).
Der Proof-of-Concept-Code (CVE-2022-22063.c) wird unter der MIT-Lizenz bereitgestellt.