
CVE-2025-21479 proof-of-concept, I think
Root exploit for the Quest 3/3S for the August 7, 2025 update and earlier, based on CVE-2025-21479.
screenshot of Magisk, Cheese, and Termux with a root shell
Rooting is dangerous. If you brick a Quest 3/3S, there is no way to repair it.
This disables all security when temp rooted.
Do NOT run apps or browse websites you don't trust.
Do NOT write to the boot or system partition. You will BRICK.
Do NOT use Magisk's "Install" feature.
You may want to back up your deviceKey, Meta Access Token and Oculus Access Token after root.
You can download an APK in the Release section.
See FreeXR's guide to rooting the Quest 3/3S.
Join FreeXR's Discord for more information.
No newer versions are supported. (Older versions can be supported with more work.)
Meta patched CVE-2025-21479 in these versions and any newer versions. They will NEVER be supported.
This repo contains the source for the command line cheese executable.
The cheese-app repo contains the source for the app.
This is based on other researchers' Adreno GPU writeups: this uses code from:
Additional info on Adreno GPUs' firmware, including how to diff the firmware and how the firmware works, comes from from Freedreno's afuc documentation by Rob Clark, Connor Abbott, and other Freedreno/Turnip contributors.
Thanks to the developers at XRBreak and FreeXR for all their help and contributions.
====
Proof-of-concept for CVE-2025-21479, demonstrating that it only affects Adreno A7xx (Snapdragon 8 Gen 1 / XR2 Gen 2 and newer) devices.
This only tests whether the device is vulnerable - getting this to actually do anything interesting would require more effort.
On unpatched Adreno A7xx devices, running this should print:
0 0
And if you run adb bugreport, in the kernel dmesg, you will see:
<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
On Adreno A6xx devices, running this prints:
41414141 42424242
https://notnow.dev/notice/AvIZRBttG7DsDhx9hw
Patched Adreno A7xx (e.g. Samsung devices after the 2025 May security update) should also print this, but I have not tested it.
# adjust path to point to your Android NDK
bash build.sh
adb push cheese /data/local/tmp
adb shell /data/local/tmp/cheese
https://notnow.dev/notice/Av4sfoQjyrxogkZ6Ya
This runs a command buffer on the Adreno GPU (Using a modified version of Project Zero's Adrenaline code)
Run CP_SET_MODE - this enables draw states to run immediately.
Run CP_SET_DRAW_STATE - this sets IB_LEVEL to 0x4, then calls a instruction buffer.
Inside the CP_SET_DRAW_STATE, run CP_SMMU_TABLE_UPDATE.
Here’s the firmware handling CP_SMMU_TABLE_UPDATE:
CP_SMMU_TABLE_UPDATE:
// get IB level
and $02, $12, 0x3
// if not 0 (kernel ring buffer), go to CP_NOP
brne $02, 0x0, #l1873
<actual SMMU modify code >
So with IB_LEVEL=4, masking 4 with 3 gives you 0, which passes the check for kernel ring buffer.
So you can change the pagetables and causes the GPU to error out.
I diffed several Samsung Galaxy firmwares using Freedreno's afuc disassembler.
The Galaxy S24 firmware was the most helpful, since its GPU firmware only differs by one version - the security fix:
https://notnow.dev/notice/AuueszvUVUQnWqMQeO
https://notnow.dev/notice/Av0kDfOUPKhqHyjyxE
Galaxy S24 firmware: gen70900_sqe.fw
https://notnow.dev/notice/Av0a7wUouVSa3EKkE4
Diffing Galaxy S24 Adreno firmware between v675 and v676 shows one type of diff:
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
Every access to $12 now ANDs with 0x7 instead of 0x3. There are no other changes.
https://gist.github.com/zhuowei/46a68b9ee53589cdeaa40c11d15d895f
Register $12 seems to be the IB level: 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
Which selects which queue of draw commands will be read. https://gitlab.freedesktop.org/mesa/mesa/-/blob/c0f56fc64cad946d5c4fda509ef3056994c183d9/src/freedreno/afuc/README.rst#id31
The Adreno 7xx hardware supports 5 queues (RB (kernel ringbuffer, priviledged), IB1, IB2, IB3, or 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
I think this diff is CVE-2025-21479. It looks like it only affects Adreno A7xx devices (Snapdragon 8 Gen 1 and above). Maybe the Qualcomm bulletin is wrong?
I'm guessing, on an Adreno A7xx device:
CP_SET_DRAW_STATECP_SMMU_TABLE_UPDATE