
CVE-2025-21479 Proof-of-Concept, denke ich
Root-Exploit für die Quest 3/3S für das Update vom 7. August 2025 und frühere, basierend auf CVE-2025-21479.
Screenshot von Magisk, Cheese und Termux mit einer Root-Shell
Rooten ist gefährlich. Wenn du eine Quest 3/3S brickst, gibt es keine Möglichkeit, sie zu reparieren.
Dies deaktiviert die gesamte Sicherheit, solange temporär gerootet ist.
Starte keine Apps und besuche keine Websites, denen du nicht vertraust.
Schreibe NICHT in die Boot- oder Systempartition. Du wirst sie BRICKEN.
Nutze NICHT die „Installieren“-Funktion von Magisk.
Du möchtest vielleicht nach dem Root ein Backup deiner deviceKey, deines Meta Access Tokens und deines Oculus Access Tokens erstellen.
Du kannst eine APK im Release-Bereich herunterladen.
Siehe FreeXRs Anleitung zum Rooten der Quest 3/3S.
Tritt für weitere Informationen dem FreeXR-Discord bei.
Neuere Versionen werden nicht unterstützt. (Ältere Versionen können mit mehr Aufwand unterstützt werden.)
Meta hat CVE-2025-21479 in diesen Versionen und allen neueren Versionen gepatcht. Sie werden NIE unterstützt.
Dieses Repository enthält den Quellcode für das Kommandozeilen-Programm cheese.
Das Repository cheese-app enthält den Quellcode für die App.
Dies basiert auf den Adreno-GPU-Ausarbeitungen anderer Forscher: Es verwendet Code von:
Zusätzliche Informationen zur Firmware der Adreno-GPUs, einschließlich der Frage, wie man die Firmware differenziert und wie die Firmware funktioniert, stammen aus Freedrenos afuc-Dokumentation von Rob Clark, Connor Abbott und anderen Freedreno/Turnip-Mitwirkenden.
Dank an die Entwickler bei XRBreak und FreeXR für all ihre Hilfe und Beiträge.
====
Proof-of-Concept für CVE-2025-21479, das zeigt, dass nur Adreno-A7xx-Geräte (Snapdragon 8 Gen 1 / XR2 Gen 2 und neuer) betroffen sind.
Dies testet nur, ob das Gerät verwundbar ist – um damit tatsächlich etwas Interessantes anzustellen, wäre mehr Aufwand nötig.
Auf ungepatchten Adreno-A7xx-Geräten sollte die Ausführung dies ausgeben:
0 0
Und wenn du adb bugreport ausführst, wirst du im Kernel-dmesg dies sehen:
<2>[146532.566695][ T933] kgsl kgsl-3d0: GPU PAGE FAULT: addr = 4000031004 pid= 0 name=(null) drawctxt=1111638594 context pid = 0
<2>[146532.566756][ T933] kgsl kgsl-3d0: context=gfx3d_user TTBR0=0x1234567841414141 (write unknown fault)
<2>[146532.566783][ T933] kgsl kgsl-3d0: FAULTING BLOCK: CP
Auf Adreno-A6xx-Geräten gibt die Ausführung dies aus:
41414141 42424242
https://notnow.dev/notice/AvIZRBttG7DsDhx9hw
Gepatchte Adreno-A7xx-Geräte (z. B. Samsung-Geräte nach dem Sicherheitsupdate vom Mai 2025) sollten dies ebenfalls ausgeben, aber ich habe es nicht getestet.
# Pfad anpassen, sodass er auf dein Android NDK zeigt
bash build.sh
adb push cheese /data/local/tmp
adb shell /data/local/tmp/cheese
https://notnow.dev/notice/Av4sfoQjyrxogkZ6Ya
Dies führt einen Befehls-Puffer auf der Adreno-GPU aus (unter Verwendung einer modifizierten Version von Project Zeros Adrenaline-Code).
Führe CP_SET_MODE aus – dies aktiviert, dass Draw-States sofort ausgeführt werden.
Führe CP_SET_DRAW_STATE aus – dies setzt IB_LEVEL auf 0x4 und ruft dann einen Befehls-Puffer auf.
Innerhalb des CP_SET_DRAW_STATE führe CP_SMMU_TABLE_UPDATE aus.
Hier ist die Firmware-Behandlung von CP_SMMU_TABLE_UPDATE:
CP_SMMU_TABLE_UPDATE:
// IB-Level abrufen
and $02, $12, 0x3
// wenn nicht 0 (Kernel-Ringpuffer), gehe zu CP_NOP
brne $02, 0x0, #l1873
<eigentlicher SMMU-Modifikationscode >
Mit IB_LEVEL=4 ergibt das Maskieren von 4 mit 3 also 0, was die Prüfung auf den Kernel-Ringpuffer besteht.
So kannst du die Seitentabellen ändern und die GPU dazu bringen, einen Fehler auszugeben.
Ich habe mehrere Samsung-Galaxy-Firmwares mit dem afuc-Disassembler von Freedreno differenziert.
Die Galaxy-S24-Firmware war am hilfreichsten, da sich ihre GPU-Firmware nur um eine Version unterscheidet – das Sicherheitsupdate:
https://notnow.dev/notice/AuueszvUVUQnWqMQeO
https://notnow.dev/notice/Av0kDfOUPKhqHyjyxE
Galaxy-S24-Firmware: gen70900_sqe.fw
https://notnow.dev/notice/Av0a7wUouVSa3EKkE4
Das Differenzieren der Adreno-Firmware des Galaxy S24 zwischen v675 und v676 zeigt eine Art von Änderung:
0163: b80300a4 CP_ME_INIT:
0163: b80300a4 fxn355:
0163: b80300a4 cread $03, [$00 + 0x0a4]
- 0164: 2a440003 and $04, $12, 0x3
+ 0164: 2a440007 and $04, $12, 0x7
0165: 98641813 ushr $03, $03, $04
0166: c860004a brne $03, b0, #l432
0167: 01000000 nop
Jeder Zugriff auf $12 verwendet nun 0x7 anstelle von 0x3 für die UND-Verknüpfung. Es gibt keine weiteren Änderungen.
https://gist.github.com/zhuowei/46a68b9ee53589cdeaa40c11d15d895f
Register $12 scheint den IB-Level zu enthalten: https://gitlab.freedesktop.org/mesa/mesa/-/blob/c0f56fc64cad946d5c4fda509ef3056994c183d9/src/freedreno/afuc/README.rst#id23 https://gitlab.freedesktop.org/mesa/mesa/-/blob/c0f56fc64cad946d5c4fda509ef3056994c183d9/src/freedreno/afuc/README.rst#id29
Dies wählt aus, welche Warteschlange der Draw-Befehle gelesen wird. https://gitlab.freedesktop.org/mesa/mesa/-/blob/c0f56fc64cad946d5c4fda509ef3056994c183d9/src/freedreno/afuc/README.rst#id31
Die Adreno-7xx-Hardware unterstützt 5 Warteschlangen (RB (Kernel-Ringpuffer, privilegiert), IB1, IB2, IB3 oder SDS): https://cs.android.com/android/platform/superproject/main/+/main:external/mesa3d/src/freedreno/registers/adreno/adreno_control_regs.xml;l=327;drc=c0867f48117dc2c18b1ae689235cb1f60b237600
https://notnow.dev/notice/Av0kDfOUPKhqHyjyxE
Ich denke, dieser Diff ist CVE-2025-21479. Es sieht so aus, als ob nur Adreno-A7xx-Geräte (Snapdragon 8 Gen 1 und höher) betroffen sind. Vielleicht ist das Qualcomm-Bulletin falsch?
Ich vermute, auf einem Adreno-A7xx-Gerät:
CP_SET_DRAW_STATE ausführen könnteCP_SMMU_TABLE_UPDATELaut dem Project-Zero-Blogbeitrag ruft die CP_INDIRECT_BUFFER-Anweisung einen indirekten Puffer mit Steuerprozessor-Anweisungen auf.
Wenn eine App die GPU verwenden möchte, enthält der RB (Kernel-Ringpuffer) des Kernels einen CP_INDIRECT_BUFFER-Befehl, der einen vom Benutzer bereitgestellten Indirect Buffer – IB1 – aufruft.
Dieser Benutzerpuffer kann seine eigenen indirekten Puffer aufrufen: IB2.
Auf A7xx gibt es außerdem IB3.
Zusätzlich gibt es auf sowohl A6xx als auch A7xx SDS, das nicht durch einen indirekten Puffer betreten wird, sondern durch CP_SET_DRAW_STATE.
https://cs.android.com/android/platform/superproject/+/android15-qpr2-release:external/mesa3d/src/freedreno/decode/cffdec.c;l=3030;drc=0dc791ed57dacf9fe3df694d7f285a8d9f942fa7 https://cs.android.com/android/platform/superproject/+/android15-qpr2-release:external/mesa3d/src/freedreno/decode/cffdec.c;l=2283;drc=0dc791ed57dacf9fe3df694d7f285a8d9f942fa7
A6xx hat RB, IB1, IB2 und SDS.
CP_SET_DRAW_STATE setzt den IB-Level auf 0x3: in a650_sqe.fw.v114 aus der Galaxy-Fold-3-Firmware:
mov $03, 0x3
or $12, $12, 0x20
call #fxn1132 // Es gibt einen Branch-Delay-Slot, also wird dies noch nicht ausgeführt...
cwrite $03, [$00 + @IB_LEVEL]
Aber A7xx hat nun RB, IB1, IB2, IB3 oder SDS.
CP_SET_DRAW_STATE setzt den IB-Level nun auf 0x4:
mov $03, 0x4
cwrite $03, [$00 + @IB_LEVEL]
0x4 & 0x3 = 0x0.
Code, der den aktuellen IB-Level prüft, wird also denken, dass SDS (Set Draw State) RB (Kernel-Ringpuffer) ist, und Befehle wie CP_SMMU_TABLE_UPDATE erlauben die Ausführung.