1 Punkte von GN⁺ 2024-03-20 | 1 Kommentare | Auf WhatsApp teilen
  • CVE-2023-6241 ist ein Logikfehler in der Speicherverwaltungseinheit der Arm-Mali-GPU, durch den eine bösartige Android-App selbst auf einem Pixel 8 mit aktiviertem Kernel-MTE beliebige Kernel-Codeausführung und Root-Rechte erlangen kann
  • Betroffen sind aktuelle Arm-Mali-GPU-Geräte mit Command Stream Frontend (CSF), darunter Google Pixel 7 und Pixel 8
  • Die Schwachstelle nutzt ein kurzes Zeitfenster aus, in dem während der Erweiterung von JIT-Speicher ein Lock freigegeben wird, um eine Inkonsistenz zwischen GPU-Mapping und dem Array der Backing-Pages zu erzeugen
  • Der Exploit nutzt ein auf freigegebene Backing-Pages verbleibendes GPU-Mapping, sorgt dafür, dass diese Seite als PGD des GPU-Kontexts wiederverwendet wird, und mappt anschließend Kernel-Speicher und Kernel-Code
  • MTE erkennt Inkonsistenzen zwischen Zeigern und Speichertags, aber dieser Angriffsablauf läuft außerhalb des MTE-Schutzbereichs, weil die GPU direkt auf physische Adressen zugreift

Umfang der Schwachstelle und Patch-Status

  • CVE-2023-6241 ist eine Arm-Mali-GPU-Schwachstelle, durch die eine bösartige Android-App auf einem Gerät beliebige Kernel-Codeausführung und Root-Rechte erlangen kann
  • Sie wurde am 15. November 2023 an Arm gemeldet und in Arm Mali driver r47p0 behoben, der am 14. Dezember 2023 veröffentlicht wurde
  • Die Android-Korrekturen wurden in das Sicherheitsupdate vom März 2024 aufgenommen
  • Betroffen sind aktuelle Arm-Mali-GPU-Geräte mit der Funktion CSF (Command Stream Frontend), als Beispiele werden Google Pixel 7 und Pixel 8 genannt
  • Es wurde bestätigt, dass der Exploit auch auf einem Pixel 8 mit aktiviertem Kernel-MTE funktioniert

Das Abwehrmodell von Arm64 MTE

  • MTE (Memory Tagging Extension) ist eine Hardwarefunktion aktueller Arm-Prozessoren, die Tags von Zeigern und Speicherblöcken vergleicht, um Speicherfehler zu erkennen
  • Arm64-Zeiger sind 64 Bit breit, der tatsächliche Adressraum von Anwendungen liegt jedoch meist bei 52 Bit oder weniger, sodass einige obere Bits zum Speichern von Tags genutzt werden können
  • Bei linearen Overflows kann sich das Tag eines benachbarten Speicherblocks vom Zeigertag unterscheiden, und bei use-after-free kann durch Tag-Änderungen beim Freigeben und erneuten Allokieren eine Inkonsistenz entstehen
  • Anders als spätere Gegenmaßnahmen wie kCFI ist MTE eine früh ansetzende Gegenmaßnahme, die Speicherfehler bereits beim ersten Auftreten erkennen soll
  • Da die Zahl der Tag-Bits begrenzt ist, lassen sich Kollisionen nicht vermeiden; selbst mit nur 4-Bit-Tags sinkt die zufällige Erfolgswahrscheinlichkeit auf 1/16
  • Werden Werte von Zeigern und Speicherblöcken über Seitenkanalangriffe wie Spectre offengelegt, kann MTE durch das Erraten des korrekten Tags umgangen werden, doch solche Leaks sind in der Regel nur für lokale Angreifer möglich
  • Derzeit erlaubt nur das Google Pixel 8 die Aktivierung von MTE in den Entwickleroptionen; standardmäßig ist MTE deaktiviert
  • Um MTE im Kernel zu aktivieren, sind zusätzliche Schritte erforderlich

Race Condition im Mali-JIT-Speicher

  • Eine Benutzer-App, die den Mali-GPU-Treiber verwendet, öffnet die Treiberdatei und erzeugt sowie initialisiert über ioctl-Aufrufe ein kbase_context-Kernel-Objekt
  • kbase_context verwaltet verschiedene Arten von Speicher, die zwischen dem GPU-Gerät und der User-Space-Anwendung gemeinsam genutzt werden
  • Speicherbereiche der Mali-GPU werden durch kbase_va_region dargestellt; nr_pages gibt die virtuelle Größe an, gpu_alloc->nents die tatsächliche Zahl der Backing-Pages
  • JIT-Speicher ist nativer Speicher, dessen Lebensdauer vom Kernel-Treiber verwaltet wird; die App kann JIT-Speicher über GPU-Befehle allokieren oder freigeben
  • Auf CSF-GPUs liegen Software-Befehle und Hardware-Befehle in unterschiedlichen Queues
    • Mit KBASE_IOCTL_KCPU_QUEUE_CREATE kann eine kbase_kcpu_command_queue erzeugt werden
    • Mit KBASE_IOCTL_KCPU_QUEUE_ENQUEUE werden Befehle in die Queue eingestellt
    • BASE_KCPU_COMMAND_TYPE_JIT_ALLOC und BASE_KCPU_COMMAND_TYPE_JIT_FREE werden für JIT-Allokation und -Freigabe verwendet
  • kbase_jit_allocate sucht im Pool freigegebener JIT-Speicherbereiche nach wiederverwendbaren Regionen und erweitert bei unzureichender physischer Größe die Backing-Pages über kbase_jit_grow
  • kbase_jit_grow kann während des Aufrufs von kbase_mem_pool_grow kctx->reg_lock und kctx->mem_partials_lock vorübergehend freigeben
  • kctx->reg_lock schützt den gleichzeitigen Zugriff auf Speicherbereiche; das Freigabefenster dieses Locks bildet daher das Race-Fenster

Trigger-Ablauf von CVE-2023-6241

  • Greift die GPU auf eine Speicherbereichsadresse zu, die nicht durch physische Seiten hinterlegt ist, entsteht ein GPU-Speicherzugriffsfehler
  • kbase_mmu_page_fault_worker prüft, ob der Bereich erweiterbar ist, und kann die benötigten Backing-Pages sofort allokieren und mappen
  • Ein JIT-Bereich erfüllt bei seiner Erzeugung die Bedingung GROWABLE_FLAGS_REQUIRED einschließlich KBASE_REG_PF_GROW und KBASE_REG_GPU_WR
  • Das Flag KBASE_REG_DONT_NEED, das beim Freigeben eines JIT-Bereichs gesetzt wird, wird früh in kbase_jit_grow durch kbase_mem_evictable_unmake entfernt
  • Dadurch kann der Fault-Handler denselben JIT-Bereich erweitern, wenn im Race-Fenster während kbase_mem_pool_grow ein GPU-Page-Fault auf diesen Bereich erzeugt wird
  • Wenn der Fault-Handler reg->gpu_alloc->nents verändert, passen die zuvor von kbase_jit_grow gespeicherten Werte old_size und delta nicht mehr zum tatsächlichen Zustand
  • Anschließend führen kbase_alloc_phy_pages_helper_locked und kbase_mem_grow_gpu_mapping mit veralteten Werten die Allokation von Backing-Pages und das GPU-Mapping aus, wodurch eine Inkonsistenz zwischen GPU-Mapping und dem pages-Array entsteht
  • Diese Race lässt sich leicht gewinnen, da kbase_mem_pool_grow große Speicherallokationen umfasst

Geänderte Angriffsmethode nach dem Patch für GHSL-2023-005

  • Bei der früheren Schwachstelle GHSL-2023-005 konnte ein anderer Thread einen JIT-Bereich per KBASE_IOCTL_MEM_COMMIT verkleinern und so old_size und delta ungültig machen
  • Nach dem Patch für GHSL-2023-005 kann die Größe von JIT-Speicher nicht mehr per KBASE_IOCTL_MEM_COMMIT ioctl verändert werden
  • Bei CVE-2023-6241 kann der Bereich im Race-Fenster nicht verkleinert, sondern nur vergrößert werden
  • Bei bloßer Vergrößerung sind lediglich einige letzte Backing-Pages nicht auf der GPU gemappt; die von Anfang an zusammenhängende Abbildung bleibt erhalten und wird nicht sofort problematisch
  • Der Exploit erzeugt durch zusätzliche GPU-Faults neue Mappings hinter einer unmapped gap und nutzt anschließend die JIT-Freigabe, um den Shrink-Punkt in diese Lücke zu legen und einen ausnutzbaren Zustand herzustellen

Fragile Annahme bei der Aufhebung von GPU-Mappings

  • kbase_mmu_teardown_pgd_pages durchläuft GPU-Seitentabellen und markiert Einträge als invalid, um GPU-Adress-Mappings zu entfernen
  • Die Funktion nimmt an, dass bei einem invaliden PTE auf höherer Ebene der gesamte von diesem Eintrag abgedeckte große Adressbereich bereits unmapped ist, und überspringt ihn daher
  • Ein einzelner Level-2-PTE deckt einen Bereich von 512 Seiten ab
  • In einem normalen kbase_va_region sind gemappte virtuelle Adressen vom Beginn des Bereichs an stets zusammenhängend und enthalten keine Lücken, weshalb dieses Überspringen dort sicher ist
  • Der Exploit für CVE-2023-6241 erzeugt jedoch eine unmapped gap zwischen Mappings und legt den Startpunkt der Verkleinerung in diese Lücke
  • Trifft kbase_mmu_teardown_pgd_pages dann auf einen invaliden Level-2-PTE, überspringt es 512 Seiten, obwohl einige dahinterliegende Adressen tatsächlich noch gemappt sein können
  • Die fälschlich übersprungenen GPU-Adressen behalten auch nach Freigabe der Backing-Pages den Zugriff auf diese physischen Seiten

Wie daraus Kernel-Codeausführung wird

  • Wird der JIT-Bereich freigegeben, werden die Backing-Pages zurückgegeben, doch das fälschlich verbleibende GPU-Mapping kann weiterhin auf die freigegebenen Seiten zugreifen
  • Die freigegebenen Backing-Pages können später für andere Kernel-Seiten wiederverwendet werden
  • Eine der verwendeten Techniken besteht darin, freigegebene Backing-Pages als PGD (page table global directory) eines GPU-kbase_context wiederverwenden zu lassen
  • Die Allokation von Backing-Pages im Mali-Treiber erfolgt hierarchisch
    • Zunächst werden Seiten aus dem kbase_mem_pool des aktuellen kbase_context entnommen
    • Reicht das nicht aus, wird pool->next_pool verwendet
    • Reicht auch das nicht aus, werden Seiten direkt über den Kernel-Buddy-Allocator allokiert
  • pool->next_pool ist ein vom Mali-Treiber verwalteter und von allen kbase_context gemeinsam genutzter Speicherpool, der auch für die PGD-Allokation von GPU-Kontexten verwendet wird
  • Wird eine freigegebene Seite als PGD wiederverwendet, kann diese PGD über die verbliebene GPU-Adresse erneut von der GPU beschrieben werden
  • Durch das Überschreiben der PGD lassen sich beliebiger Kernel-Speicher und Kernel-Code in die GPU mappen
  • In diesem Zustand ist es möglich, Kernel-Code zu überschreiben und so beliebige Kernel-Codeausführung zu erreichen sowie Kernel-Daten zu lesen und zu schreiben, um Prozess-Credentials zu ändern und SELinux zu deaktivieren
  • Exploit und Konfigurationsnotizen für Pixel 8 sind im GitHub Security Lab Repository veröffentlicht

Warum eine Umgehung von MTE möglich ist

  • Dieser Exploit-Ablauf benötigt keine gesonderte, MTE-spezifische Umgehungsstufe
  • MTE prüft, ob die Tags des von einem Zeiger referenzierten Speicherblocks übereinstimmen, um fehlerhafte Dereferenzierungen zu erkennen
  • Beim Triggern von CVE-2023-6241 entsteht zwar eine Inkonsistenz zwischen dem pages-Array und dem GPU-Mapping, betrachtet man beide jedoch jeweils für sich, enthalten sie keine invaliden Einträge
  • Wenn kbase_mmu_teardown_pgd_pages das Entfernen eines GPU-Mappings überspringt, bleibt die physische Adresse einer freigegebenen Speicherseite in der GPU-Seitentabelle erhalten
  • Wenn die GPU auf diese freigegebene Seite zugreift, spricht sie die physische Adresse direkt an und durchläuft keine Prüfung von Zeigerdereferenzierungen
  • Auch der Einfluss von MTE auf GPU-Speicherzugriffe ist nicht eindeutig geklärt
  • Dadurch umgeht dieser Bug den MTE-Schutz, indem er den Pfad nutzt, über den der Coprozessor GPU direkt auf physischen Speicher zugreift

Verbleibende Angriffsfläche nach MTE

  • CVE-2023-6241 zeigt, dass selbst auf einem Pixel 8 mit aktiviertem Kernel-MTE ein einzelner Bug für beliebige Kernel-Codeausführung ausreichen kann
  • MTE ist ein wichtiger Fortschritt bei der Abwehr von Speicherfehlern und kann viele Memory-Corruption-Schwachstellen praktisch unausnutzbar machen, ist jedoch kein Allheilmittel
  • In diesem Fall wird MTE umgangen, indem die GPU direkt auf physischen Speicher zugreift
  • Je mehr Hardware- und Software-Gegenmaßnahmen auf CPU-Seite hinzukommen, desto stärker können Coprozessoren und ihre Kernel-Treiber weiterhin eine mächtige Angriffsfläche bleiben

1 Kommentare

 
GN⁺ 2024-03-20
Meinungen auf Hacker News
  • Der Kernpunkt hier ist, dass die GPU schon seit Langem ein Problemfall für Android ist.
    Die GPU hat sehr weitreichenden Zugriff auf den AP und kann die davor platzierten Abhilfemaßnahmen praktisch umgehen. Bugs im Mapping-Code des Treibers führen zu mächtigen Angriffs-Primitives und wurden auch in realen Exploits in freier Wildbahn wiederholt ausgenutzt. Letztlich dürfte sich daran kaum etwas Grundlegendes ändern, bis die Architektur neu entworfen wird.

    • Meiner Meinung nach sollten die halbgar gebauten mobilen GPUs aufhören, eigene MMUs einzubauen, und stattdessen eine standardisierte I/O-MMU verwenden.
    • Was bedeutet AP hier?
  • Das Interessante an dieser Schwachstelle ist, dass es sich um einen Logikfehler in der Speicherverwaltungseinheit der Arm-Mali-GPU handelt und dass sich damit die Memory Tagging Extension umgehen lässt.
    Der Rest des Artikels scheint jedoch zu erklären, dass die eigentliche Ursache eine Race Condition ist und Use-after-Free nur deren Folge.

  • War auch eine GrapheneOS-Installation vor dem März-Update betroffen?

    • Eines der Hauptziele von GrapheneOS ist es, Sicherheitsupdates so schnell wie möglich auszuliefern. Wenn der Patch also upstream eingespielt wurde, war er mit ziemlicher Sicherheit in GrapheneOS enthalten.
      Manchmal übernimmt GrapheneOS AOSP-Sicherheitspatchlevel schon vor dem Release oder backportiert auch Sicherheitsfixes aus noch nicht veröffentlichtem AOSP- oder Kernel-Quellcode.
    • Ich hatte gedacht, das sei ein Problem nahe an der Hardware in der GPU, vielleicht im Zusammenhang mit Firmware, und würde daher auch nach dem März-Update noch Auswirkungen haben. Dieses Update betraf ja den Bluetooth-Stack.
      Korrektur: Kann ignoriert werden. Ich habe das mit dem jüngsten GrapheneOS-Blogbeitrag verwechselt, in dem es darum ging, dass „MTE auf alle System-Apps angewendet wird“. GrapheneOS hat im Release 2024030600 das „vollständige Sicherheitspatchlevel 2024-03-05“ übernommen, daher scheint auch dieser Patch enthalten zu sein.
  • Probabilistische Arm-MTE-Speichersicherheit ist ein Sprungbrett hin zu deterministischer CHERI-Hardware, https://saaramar.github.io/memory_safety_blogpost_2022/ und https://news.ycombinator.com/item?id=39668053
    Die richtigen Mitigations sollten auf die primären Angriffsprimitive zielen, also auf die eigentlichen Ursachen der Bugs. Als Hardware-Lösungen gibt es CHERI (Morello, CheriIoT) und MTE; als Software-Mitigations kalloc_type+dataPAC, AUTOSLAB, Firebloom, GuardedMemcpy, CastGuard und die Reduzierung der Angriffsfläche; als sichere Programmiersprachen Rust und Swift. MTE und CHERI greifen gut ineinander und helfen, Bugs in diesem Bereich an der Wurzel zu beseitigen. MSR, MSRC und Azure Silicon haben darauf gedrängt, CHERI bis hinunter zur kleinsten RISC-V-Kernspezifikation, RISC-V32E, zu verkleinern.
    Microsoft Research hat einen CHERI-Hardware/Software-Stack für IoT-Geräte als Open Source veröffentlicht, https://msrc.microsoft.com/blog/2023/02/first-steps-in-cheri...
    Ein CHERI-basierter Mikrocontroller zielt darauf ab, sehr starke Sicherheitsgarantien zu erreichen, indem Instruktionssatzarchitektur (ISA), Application Binary Interface (ABI), Isolationsmodell und der Kern des Software-Stacks gemeinsam entworfen werden. Dieser Mikrocontroller erreicht deterministische Mitigation räumlicher Sicherheit über CHERI-ISA-Funktionen, deterministische Mitigation zeitlicher Sicherheit für Heap und Stacks zwischen Compartments über Load Barriers, Zeroing, Reclamation und 1-Bit-Information-Flow-Control sowie feingranulare Kompartimentierung über zusätzliche CHERI-ISA-Funktionen und einen kleinen Monitor.
    David Chisnall, U of Cambridge, https://lobste.rs/s/gnjx2n/c_can_be_memory_safe#c_9ohzku via https://eclypsium.com/blog/a-faster-path-to-memory-safety-ch...
    „Es gibt rund 13 Milliarden Zeilen Open-Source-C/C++-Code, die in verschiedene Trusted Computing Bases eingehen; mit proprietärem Code ist es noch mehr. Selbst wenn ab sofort alle aufhören würden, C/C++ zu schreiben, und sich alle Softwareingenieure darauf konzentrieren würden, Legacy-Code in sicheren Sprachen neu zu schreiben, würde es 5 bis 10 Jahre dauern, alles zu ersetzen. Und dabei würden wahrscheinlich viele Logikfehler entstehen, weil lange erprobter Code durch neuen Code ersetzt würde, der andere Algorithmen und Datenstrukturen braucht, um zu den erlaubten Idiomen sicherer Sprachen zu passen.“
    „Wenn wir nicht neu schreiben, sondern nur aufhören, C/C++-Code zu schreiben, dauert es bei der üblichen Austauschrate von Code etwa 50 Jahre, bis Trusted Computing Bases vollständig sicher sind. Wenn sich nicht alle darauf einigen, mit C/C++ aufzuhören, sind es mindestens 100 Jahre.“
    „Wenn dagegen große CPU-Hersteller innerhalb von 5 Jahren CHERI-CPUs ausliefern, werden innerhalb von 15 Jahren ab heute die meisten Maschinen, insbesondere hochwertige Maschinen, Speichersicherheit haben, ohne dass Programmierer ihr Verhalten ändern müssen.“

    • Wenn man sich für CHERI in Einsatzbereichen ähnlich Embedded/IoT interessiert: lowRISC baut einige FPGA-basierte Evaluierungsplattformen für CHERIoT: https://www.sunburst-project.org/
      Die erste ist das Sonata-System: https://github.com/lowRISC/sonata-system. Es besteht aus einem dedizierten PCB mit FPGA sowie mehreren Peripheriegeräten und Headern. Das PCB-Design ist abgeschlossen und soll über Mouser erhältlich sein; sogar das Board-Layout ist Open Source, sodass man es bei Bedarf selbst bestücken kann. Derzeit wird am RTL für das FPGA gearbeitet. Wenn es fertig ist, erhält man ein CHERIoT-basiertes mikrocontrollerartiges System samt Dokumentation und Tools.
      Zusätzlich entsteht auch das Symphony-System, das Sonata mit dem OpenTitan-Earl-Grey-Root-of-Trust kombiniert: https://github.com/lowRISC/symphony-system
    • Es gibt auch Solaris SPARC ADI. Wegen des aktuellen Zustands von Oracle und Solaris SPARC ist es größtenteils in Vergessenheit geraten, was schade ist.
    • Das ist ein Hardware-Bug außerhalb der CPU, daher weiß ich nicht, wie CHERI helfen soll.
      Außerdem war CHERI, als ich zuletzt nachgesehen habe, nicht sound. Man konnte darauf immer noch Speicherfehler schreiben; ist das inzwischen behoben?
    • „5 bis 10 Jahre, um alles zu ersetzen“ klingt, wenn damit Kalenderjahre gemeint sind, viel zu optimistisch.
      Allein die Bikeshedding-Debatte würde vermutlich so lange dauern.
    • Das Grundproblem scheint zu sein, dass der Nutzer bösartigen Code ausführt und irgendeine MMU-Hash-Kollision ausnutzt.
      Dieser Exploit dürfte sich in den meisten Sprachen schreiben lassen, einschließlich Rust.
  • Hardware ist so schlecht? Meine Güte ...

    • GPU-Hardware ist voller Bugs. Einen neuen Tape-out macht man nur, wenn ein Problem im Treiber nicht zu vertretbaren Kosten umgangen werden kann.
      Das funktioniert, weil GPUs keinen so relativ direkten Hardwarezugriff erlauben wie CPUs.
    • Das ist ein Treiber-Bug, der auf der CPU läuft.
  • Hervorragende Forschung und ein guter Artikel; dass er im GitHub-Blog erschienen ist, ist etwas überraschend, aber auch erfreulich.
    Weiß jemand, welchen „geschäftlichen Grund“ GitHub dafür hat, solche Forschung zu betreiben? Ich meine nicht, dass es zwingend einen geschäftlichen Grund geben muss, aber es hier zu sehen, hat mich etwas überrascht.

    • Man Yue Mo arbeitete vor der Übernahme durch GitHub bei Semmle (https://blog.sonatype.com/steps-to-responsible-disclosure, https://github.blog/2019-09-18-github-welcomes-semmle/)
      Diese Forschungsfunktion ging im GitHub Security Lab auf. Semmle entwickelte CodeQL, das heute von GitHub angeboten wird (https://docs.github.com/en/code-security/code-scanning/intro...). GitHub und Microsoft möchten CodeQL mit „tiefen Sicherheitseinblicken“ verknüpfen (https://www.microsoft.com/en-us/security/blog/2023/11/02/ann...)
      Deshalb finanzieren sie weiterhin solche neuartigen Sicherheitsforschungen, wofür Sicherheitspraktiker in der Branche dankbar sind.
    • Diese Arbeit stammt aus GitHubs Security Lab: https://securitylab.github.com/
    • Durch die Übernahme durch Microsoft entstanden Ressourcen, um diese Art von Forschung zu fördern.
      Es gibt auch eine GitHub-App, und die Sicherheit dieser App liegt nicht außerhalb des Zuständigkeitsbereichs von GitHub. Wenn ein Angreifer eine App installieren kann, die sich auf einem Telefon versteckt, kann er im Namen des Nutzers allerlei Dinge tun. Bei jemandem mit Einfluss auf GitHub könnte der Schaden ziemlich groß sein; solche Schwachstellen zu finden, liegt also auch im Interesse von GitHub.
    • GitHub hat auch gehostete Actions-Runner für Arm.
      Daher könnte GitHub daran interessiert sein, Sicherheitsfunktionen von Arm-Hardware für Sandboxing mithilfe von MTE zu prüfen und zu validieren.
    • Ich sehe das im Grunde eher als Grundlagenforschung [0].
      Kurzfristig betrachtet braucht das Produkt GitHub nicht unbedingt Android-Sicherheitsexperten. Langfristig gibt es aber potenzielle Vorteile.
      [0]: https://en.wikipedia.org/wiki/Basic_research
  • Es ist erstaunlich, dass es noch keine Fälle gab, in denen man CPUs und Telefone mit kaum oder gar keiner GPU gebaut und sie Business-Phones genannt hat.
    Die Vorteile bei Sicherheit, Kosten und Stromverbrauch scheinen offensichtlich.

    • Der offensichtliche Nachteil ist, dass es keinen hochauflösenden Touchscreen gäbe und man damit zu Blackberry oder Palm Treo zurückkehren würde. Genau solche Geräte wurden tatsächlich als Business-Phones verkauft.