
Exploit Dirty Pagetable per CVE-2025-8045
Un exploit di escalation dei privilegi locale per CVE-2025-8045, una use-after-free nel driver del kernel della GPU Arm Mali (kbase). Un processo locale non privilegiato mette in gara il percorso di dump della coda KCPU del CSF per liberare e riallocare un cpu_queue.buffer, trasforma l'allocazione pendente in una tabella delle pagine di sua proprietà ("dirty pagetable") e usa questa primitiva per ottenere lettura/scrittura fisica arbitraria del kernel — culminando in una shell di root con SELinux impostato a permissive.
Testato su Pixel 7 Pro (build
BP3A.250905.014). Gli offset hardcoded inexploit.csono calibrati per questo target; altri dispositivi/build richiedono di ricavare nuovamente gli offset (vedi Tuning e portabilità).
CVE-2025-8045 è una use-after-free nei driver del kernel Arm Valhall e 5th Gen GPU Architecture (r53p0–r54p1). Un processo locale non privilegiato può pilotare le operazioni di elaborazione della GPU in modo da lasciare il driver a operare su memoria già liberata, aprendo la porta a divulgazione della memoria del kernel, corruzione ed esecuzione di codice.
Questo exploit raggiunge il bug tramite l'interfaccia della coda KCPU del CSF esposta da /dev/mali0:
CQS_WAIT insoddisfacibile seguito da un FENCE_SIGNAL. L'attesa blocca la coda così che il timer del fence scatti più tardi, su un confine prevedibile del bucket della timer-wheel.KBASE_IOCTL_CS_CPU_QUEUE_DUMP guida kbase_csf_cpu_queue_dump_buffer(). Far gareggiare la transizione di stato della coda (ISSUED → COMPLETE/PENDING) contro il percorso di dump libera cpu_queue.buffer mentre è ancora referenziato — la UAF.L'exploit è un exploit di temporizzazione: prima calibra la scadenza, poi la prevede a ogni round e lancia una "wave" di chiamate di dump innocue per allargare la finestra di gara attorno al momento della liberazione.
| Fase | Cosa succede |
|---|---|
| Calibrazione | Il round 1 misura il fronte ISSUED→COMPLETE per apprendere la fase del bucket della timer-wheel. |
| Previsione + sweep | I round successivi prevedono la scadenza e spazzano l'offset di lettura ±ms per centrare esattamente la liberazione. |
| Wave | 64 thread accumulano chiamate CS_CPU_QUEUE_DUMP su csf.lock per racchiudere la scadenza e allungare la finestra. |
| Recupero | Svuota preventivamente le free list UNMOVABLE, poi spruzza pagine GPU marcate così che il blocco liberato torni sotto il nostro controllo. |
| Dirty pagetable | Libera di nuovo e spruzza immediatamente tabelle delle pagine CPU nella stessa pagina; l'allocazione GPU ora è in alias con una tabella attiva di ultimo livello. |
| Lettura/scrittura arbitraria | Una PTE di una finestra mai riutilizzata viene puntata a pagine fisiche del kernel; la TLB viene forzata a un flush tramite un round-trip PROT_NONE su un grande mapping scratch. |
| Root | Azzera selinux_state.enforcing, applica la patch a sel_read_enforce con commit_creds(init_cred), rilascia un processo figlio in attesa che esegue una shell di root. |
Poiché una pagina finisce per essere sia un'allocazione Mali sia una tabella delle pagine CPU attiva, il processo rimane parcheggiato per sempre invece di uscire — liberarla sarebbe un double-free e manderebbe in panic il kernel.
# Android / arm64 (NDK)
aarch64-linux-android31-clang -O2 -o exploit exploit.c
./exploit
In caso di successo ottieni una shell di root (uid=0) con SELinux permissive. Flusso di esempio:
[*] pid=... cpus=8 wave=64 harvest cpu=7 rounds=256
[*] round 1 calibrate deadline t0+... ms phase ... ms
[*] round N read +... us
[+] UAF page: spray region R page P @ ..., 1 live descriptor
[+] entry 0 = ... -- a CPU page table, writable through the GPU
[+] alias: dirty pagetable
[+] selinux_state.enforcing = 0 @ phys ...
[+] sel_read_enforce patched @ phys ...
[+] root shell: uid=0 euid=0
Se esegue tutti i round senza successo, cpu_queue.c:71 in dmesg indica che la gara sta atterrando ma il recupero non è andato a segno — regola i parametri di reclaim/wave.
I valori in exploit.c sono calibrati per il Pixel 7 Pro, build BP3A.250905.014. Gli offset e le costanti sono specifici di dispositivo/kernel e devono essere ricalcolati per qualsiasi altro target:
KERNEL_PA_BASE, SEL_READ_ENFORCE, INIT_CRED, COMMIT_CREDS, SELINUX_STATE — offset dei simboli/fisici del kernel.ARM64_PTE_FLAGS — template del descrittore di ultimo livello per la configurazione MMU del target.WAVE_*, SWEEP_*, BUCKET_NS, WAIT_NS, dimensioni degli spray — manopole per il timing della gara e l'heap-grooming.Aggiorna al rilascio del driver corretto fornito da Arm per rimediare.
Questo codice è pubblicato esclusivamente per ricerca sulla sicurezza difensiva, ingegneria delle detection e istruzione. Non eseguirlo su sistemi che non possiedi o per cui non hai un'autorizzazione scritta esplicita al test. L'autore non si assume alcuna responsabilità per un uso improprio o per qualsiasi danno causato. Usarlo su sistemi senza permesso è illegale.