
Exploit locale di root per CVE-2025-21479 (Adreno KGSL) su iQOO Neo8 (SM8475) - lettura/scrittura della memoria fisica, disabilita SELinux, avvia una shell di root
针对 CVE-2025-21479 的本地提权实验代码,目标是 vivo V2301A(iQOO Neo8 / PD2301,Snapdragon 8+ Gen 1 / SM8475,Adreno A730,Android 14,GKI 内核 5.10)上的 Qualcomm Adreno GPU(KGSL)。
In linea di principio, l'exploit sfrutta il comando CP_SMMU_TABLE_UPDATE di KGSL per pilotare l'SMMU della GPU,
ottenendo la capacità di lettura e scrittura arbitraria della memoria fisica, per poi disattivare SELinux, individuare i simboli del kernel e ottenere una shell
root—il tutto senza necessità di flashing e senza dipendere dallo sblocco del Bootloader.
Solo per ricerca sulla sicurezza su dispositivi di tua proprietà o per i quali hai ottenuto autorizzazione.
and $12, 0x3) è difettoso e classifica erroneamente i pacchetti Self-Draw-State (SDS) come
RingBuffer (RB). Pertanto, inviando in user space un falso CP_SMMU_TABLE_UPDATE all'interno di un blocco SDS,
è possibile sovrascrivere il TTBR0 della GPU, facendo puntare la tabella delle pagine della GPU a una pagina fisica arbitraria — da quel momento la GPU
può leggere e scrivere qualsiasi memoria fisica.stabilize_rw la mappatura viene consolidata in una regione automappata da 2 MB,
che supporta letture rapide in grandi quantità (fast_pread_bytes ecc.).selinux_state.enforcing nella memoria fisica.
Successivamente viene eseguito il dump dell'immagine del kernel dalla base fisica fissa 0xA8000000 (limite predefinito 43 MB) —
SM8475 non ha KASLR fisico — e le strutture kallsyms vengono analizzate direttamente dal dump grezzo
(riconoscimento automatico di big/little endian), quindi anche il KASLR virtuale non ha effetto.prepare_kernel_cred(0) →
commit_creds(), con disattivazione di seccomp) viene applicata una patch a __do_sys_capset. Il processo figlio generato con fork
chiama capset() → diventa uid 0 → ripristina il codice kernel sovrascritto → il processo figlio riesegue il comando specificato
nel dominio u:r:shell:s0 (predefinito sh). Il codice kernel alla fine
risulta identico byte per byte a prima dell'esecuzione.| Modello | vivo V2301A (iQOO Neo8, nome in codice PD2301, scheda madre taro) |
| SoC | SM8475 (Snapdragon 8+ Gen 1) + Adreno 730 |
| Android | 14 (UP1A.231005.007, SDK 34, qssi-user) |
| Kernel | 5.10.198-gki-gfb2f5774872c |
| SELinux | Enforcing (disattivato a runtime da questo strumento) |
Le informazioni complete sul dispositivo sono in device_info.txt.
├── source/
│ ├── cheese.c # 漏洞利用主程序(include 了下面两个文件)
│ ├── kallsyms_lookup.c # 针对原始内核映像的 kallsyms 解析器
│ └── adrenaline.h # KGSL ioctl / 命令定义(作者 hawkes)
├── exploit # 预编译 arm64 二进制(动态链接,minSdk 21,
│ # NDK r30-beta2)
├── device_info.txt # 用于调参的目标设备信息
└── README.md
Nota: cheese.c eseguirà #include di kallsyms_lookup.c e adrenaline.h,
durante la compilazione i tre file devono trovarsi nella stessa directory.
Qualsiasi Android NDK sufficientemente recente (r25+) va bene, esempio:
# 静态链接(自包含、任意 API 等级可运行;体积较大)
aarch64-linux-android34-clang -o cheese source/cheese.c -static
# 动态链接(体积小,依赖设备自带的 libc;API 等级需匹配设备)
aarch64-linux-android34-clang -o exploit_dyn source/cheese.c
# 若要兼容 API 21+ 设备,请改用 aarch64-linux-android21-clang
#推送exploit
adb push exploit /data/local/tmp/
#运行exploit
adb shell
chmod +x /data/local/tmp/exploit
/data/local/tmp/exploit
教程 dettagliato qui (all'interno è presente uno strumento one-click)
In caso di successo si ottiene una shell con uid=0, e il SELinux di questa sessione è stato disabilitato. Il processo, dopo aver completato
l'escalation dei privilegi, rieseguirà argv[1..] (predefinito sh). Ogni esecuzione presenta un conto alla rovescia
("pte wait 3 second") e un avanzamento della lettura del kernel di 43 MB ("Read X / 43 MB").

| Variabile | Funzione |
|---|---|
CHEESE_PHYADDR=<phys> | Forza l'indirizzo fisico di base del kernel (salta la tabella di rilevamento integrata gPhyAddrs). |
CHEESE_ATTEMPT=<n> | Usa gPhyAddrs[n] invece di gPhyAddrs[0]; dopo il fallimento dell'inizializzazione della GPU, maybe_retry incrementa automaticamente e riprova. |
CHEESE_SWAPPER_PG_DIR_OFF=<off> | Salta la scansione di swapper_pg_dir e usa direttamente questo offset assoluto. |
CHEESE_READ_FULL_KERNEL=1 | Legge l'intera immagine del kernel (il limite predefinito di lettura è DEFAULT_KERNEL_SIZE_MB = 43 MB). |
CHEESE_KALLSYMS_MAX_MB=<MB> | Sovrascrive il limite di lettura di kallsyms. |
CHEESE_FORCE_MANUAL_PATCHFINDER=1 | Forza l'uso del patchfinder manuale come fallback (init_cred, prepare_kernel_cred). |
CHEESE_SKIP_GPU=1 | Salta la fase di lettura/scrittura della GPU (solo per debug). |
CHEESE_NO_RETRY=1 | Esce direttamente dopo un fallimento, senza riprovare con un altro numero. |
A causa del meccanismo speciale dei modelli vivo, su iQOO Neo8 è necessario disabilitarlo per mantenere stabile il permesso di root (il principio specifico non viene spiegato qui. Potrebbe non essere universale per altri modelli vivo e versioni del kernel; è necessario estrarre vr.ko e analizzarlo in reverse manualmente). Prima di eseguire le seguenti operazioni, assicurarsi che la sessione shell corrente abbia già ottenuto i permessi di root.
#备份原始apanic
dd if="$(readlink -f /dev/block/by-name/apanic)" of=/sdcard/apanic_full.bin
#adb shell内执行
adb pull /sdcard/apanic_full.bin ./
#主机端执行
#禁用vr.ko(风险自行评估)
printf '\370\037\000\000\000\000\000\000\000\000\000\000' | dd of=$(readlink -f /dev/block/by-name/apanic) bs=1 seek=$(( $(blockdev --getsize64 /dev/block/by-name/apanic) - 65472 )) conv=notrunc && sync
Se successivamente un riavvio a freddo del telefono causa la perdita dei permessi di root, è sufficiente rieseguire l'exploit e poi eseguire il jailbreak
$(find /data/app -type f -name "libksud.so" | grep resukisu) late-load --kmi android12-5.10
Le costanti specifiche del dispositivo si trovano all'inizio di source/cheese.c:
KERNEL_PHYS_BASE — indirizzo fisico di base del kernel (predefinito 0xA8000000, SM8475)IDMAP_PG_DIR_OFFSET — offset di idmap_pg_dir (predefinito 0x245a000)selinux_state_offset — offset usato per individuare selinux_state (predefinito
0x729030, indirizzo fisico effettivo = indirizzo fisico di idmap_pg_dir + questo offset)gPhyAddrs[] — indirizzi fisici di base candidati provati in sequenzaDEFAULT_KERNEL_SIZE_MB — valore di fallback / limite massimo per la lettura del kernelPrerequisiti: GPU della serie Adreno A730/A7xx (con firmware interessato) e sistema del dispositivo senza la patch di sicurezza rilasciata da Qualcomm a giugno 2025, kernel con kallsyms risolvibile dal dump fisico e assenza di KASLR fisico.