
CVE-2025-21479 prova de conceito, eu acho
Root exploit para o Quest 3/3S para a atualização de 7 de agosto de 2025 e anteriores, baseado em CVE-2025-21479.
captura de tela do Magisk, Cheese e Termux com um shell root
Rootear é perigoso. Se você brickar um Quest 3/3S, não há como repará-lo.
Isso desabilita toda a segurança quando está com root temporário.
NÃO execute aplicativos ou navegue em sites que você não confia.
NÃO escreva na partição de boot ou sistema. Você irá BRICKAR.
NÃO use o recurso "Instalar" do Magisk.
Você pode querer fazer backup de sua deviceKey, Meta Access Token e Oculus Access Token após o root.
Você pode baixar um APK na seção Release.
Veja o guia do FreeXR para rootear o Quest 3/3S.
Participe do Discord do FreeXR para mais informações.
Nenhuma versão mais recente é suportada. (Versões mais antigas podem ser suportadas com mais trabalho.)
A Meta corrigiu o CVE-2025-21479 nessas versões e em quaisquer versões mais recentes. Elas NUNCA serão suportadas.
Este repositório contém o código-fonte para o executável de linha de comando cheese.
O repositório cheese-app contém o código-fonte para o aplicativo.
Baseado em writeups de outros pesquisadores sobre GPU Adreno: este usa código de:
Informações adicionais sobre o firmware das GPUs Adreno, incluindo como diferenciar o firmware e como ele funciona, vêm da documentação afuc do Freedreno, por Rob Clark, Connor Abbott e outros contribuidores do Freedreno/Turnip.
Agradecimentos aos desenvolvedores da XRBreak e do FreeXR por toda a ajuda e contribuições.
====
Prova de conceito para CVE-2025-21479, demonstrando que afeta apenas dispositivos Adreno A7xx (Snapdragon 8 Gen 1 / XR2 Gen 2 e mais novos).
Isso apenas testa se o dispositivo é vulnerável - fazer isso realmente fazer algo interessante exigiria mais esforço.
Em dispositivos Adreno A7xx não corrigidos, executar isso deve imprimir:
0 0
E se você executar adb bugreport, no kernel dmesg, você verá:
<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
Em dispositivos Adreno A6xx, executar isso imprime:
41414141 42424242
https://notnow.dev/notice/AvIZRBttG7DsDhx9hw
Adreno A7xx corrigido (por exemplo, dispositivos Samsung após a atualização de segurança de maio de 2025) também deve imprimir isso, mas não testei.
# 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
Isso executa um buffer de comando na GPU Adreno (usando uma versão modificada do código Adrenaline do Project Zero)
Executa CP_SET_MODE - isso permite que os estados de desenho sejam executados imediatamente.
Executa CP_SET_DRAW_STATE - isso define IB_LEVEL como 0x4, então chama um buffer de instrução.
Dentro de CP_SET_DRAW_STATE, executa CP_SMMU_TABLE_UPDATE.
Aqui está o tratamento do firmware para 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 >
Então, com IB_LEVEL=4, mascarar 4 com 3 dá 0, o que passa na verificação do ring buffer do kernel.
Então você pode alterar as tabelas de página e fazer a GPU gerar erro.
Eu diferenciei vários firmwares Samsung Galaxy usando o desmontador afuc do Freedreno.
O firmware do Galaxy S24 foi o mais útil, já que seu firmware de GPU difere apenas por uma versão - a correção de segurança:
https://notnow.dev/notice/AuueszvUVUQnWqMQeO
https://notnow.dev/notice/Av0kDfOUPKhqHyjyxE
Firmware do Galaxy S24: gen70900_sqe.fw
https://notnow.dev/notice/Av0a7wUouVSa3EKkE4
Diferenciar o firmware Adreno do Galaxy S24 entre v675 e v676 mostra um tipo de diferença:
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
Cada acesso a $12 agora faz AND com 0x7 em vez de 0x3. Não há outras alterações.
https://gist.github.com/zhuowei/46a68b9ee53589cdeaa40c11d15d895f
O registrador $12 parece ser o nível IB: 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
Que seleciona qual fila de comandos de desenho será lida. https://gitlab.freedesktop.org/mesa/mesa/-/blob/c0f56fc64cad946d5c4fda509ef3056994c183d9/src/freedreno/afuc/README.rst#id31
O hardware Adreno 7xx suporta 5 filas (RB (ringbuffer do kernel, privilegiado), IB1, IB2, IB3 ou 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
Acho que essa diferença é o CVE-2025-21479. Parece que afeta apenas dispositivos Adreno A7xx (Snapdragon 8 Gen 1 e superiores). Talvez o boletim da Qualcomm esteja errado?
Estou supondo, em um dispositivo Adreno A7xx:
CP_SET_DRAW_STATECP_SMMU_TABLE_UPDATEDe acordo com a postagem do blog do Project Zero, a instrução CP_INDIRECT_BUFFER chama um buffer indireto de instruções do processador de controle,
Quando um aplicativo quer usar a GPU, o RB (ring buffer do kernel) do kernel conterá um comando CP_INDIRECT_BUFFER que chama um Indirect Buffer fornecido pelo usuário - IB1.
Esse buffer de usuário pode chamar seus próprios buffers indiretos: IB2.
No A7xx, também há IB3.
Além disso, tanto no A6xx quanto no A7xx, existe SDS, que não é acessado por buffer indireto, mas por 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 tem RB, IB1, IB2 e SDS.
CP_SET_DRAW_STATE define o nível IB como 0x3: em a650_sqe.fw.v114 do firmware do Galaxy Fold 3:
mov $03, 0x3
or $12, $12, 0x20
call #fxn1132 // there's a branch delay slot, so this isn't executed yet...
cwrite $03, [$00 + @IB_LEVEL]
Mas o A7xx agora tem RB, IB1, IB2, IB3 ou SDS.
CP_SET_DRAW_STATE agora define o nível IB como 0x4:
mov $03, 0x4
cwrite $03, [$00 + @IB_LEVEL]
0x4 & 0x3 = 0x0.
Então o código que verifica o nível IB atual pensará que SDS (set draw state) é RB (ring buffer do kernel), e comandos como CP_SMMU_TABLE_UPDATE permitirão a execução.