Pixel BigWave BIGO timeout race UAF → 2KB kernel write from mediacodec

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

TL;DR

  • Dal contesto confinato da SELinux mediacodec, /dev/bigwave (Pixel AV1 hardware accelerator) è raggiungibile. Un backlog di job fa sì che BIGO_IOCX_PROCESS colpisca il suo 16s wait_for_completion_timeout() e ritorni mentre il worker thread in parallelo estrae dalla coda la stessa struttura inline job.
  • La chiusura dell’FD libera immediatamente struct bigo_inst (che incorpora struct bigo_job). Il worker ricostruisce inst = container_of(job, ...) e poi usa campi già liberati come job->regs dentro bigo_run_job(), causando una Use-After-Free on the inline job/inst.
  • bigo_pull_regs(core, job->regs) esegue memcpy_fromio(regs, core->base, core->regs_size). Riciclando lo slab liberato e sovrascrivendo job->regs, un attaccante ottiene un ~2144-byte arbitrary kernel write verso un indirizzo scelto, con controllo parziale dei byte pre-programmando i valori dei registri prima del timeout.
  • Tracciato come CVE-2025-36934; corretto nelle build 2026-01-05 Pixel/2025-12-01 ASB.

Attack surface mapping (SELinux → /dev reachability)

  • Usare strumenti come DriverCartographer per enumerare i device node accessibili da un dato dominio SELinux. Nonostante la policy restrittiva di mediacodec (i software decoder dovrebbero restare in un contesto isolato), /dev/bigwave è rimasto raggiungibile, esponendo una vasta superficie di attacco al codice post-media-RCE.

Vulnerability: BIGO_IOCX_PROCESS timeout vs worker

  • Flusso: ioctl copia il buffer dei registri utente in job->regs, mette in coda l’job inline, poi viene chiamato wait_for_completion_timeout(..., 16s). Al timeout prova a dequeue/cancel e ritorna nello spazio utente.
  • Nel frattempo bigo_worker_thread potrebbe aver appena estratto dalla coda lo stesso job:
inst = container_of(job, struct bigo_inst, job);
bigo_push_regs(core, job->regs);
...
bigo_pull_regs(core, job->regs);   // memcpy_fromio(regs, core->base, core->regs_size)
*(u32 *)(job->regs + BIGO_REG_STAT) = status;
  • Se userspace chiude la FD dopo il timeout, inst/job vengono liberati mentre il worker continua a usarli → UAF. Non esiste sincronizzazione che leghi la durata della FD al puntatore job del thread worker.

Panoramica dello sfruttamento

  1. Backlog + timeout: Accoda abbastanza job in modo che il worker venga ritardato, poi esegui BIGO_IOCX_PROCESS e lascia che raggiunga il percorso di timeout di 16s.
  2. Free while in use: Non appena l’ioctl ritorna, esegui close(fd) per liberare inst/job mentre il worker sta ancora eseguendo il job rimosso dalla coda.
  3. Reclaim + pointer control: Spray reclaimers (e.g., Unix domain socket message allocations) per occupare lo slot slab liberato e sovrascrivere l’job inline, in particolare job->regs.
  4. Arbitrary write: Quando bigo_pull_regs() viene eseguito, memcpy_fromio() scrive core->regs_size (~2144 bytes) da MMIO nell’indirizzo fornito dall’attaccante in job->regs, producendo un grande write-what-where senza una perdita di KASLR.
  5. Data shaping: Poiché i registri vengono prima programmati dai dati utente (bigo_push_regs), impostali in modo che l’hardware non esegua, mantenendo l’immagine dei registri ricopiata vicina a byte controllati dall’attaccante.

Scheletro PoC minimo (backlog bloccante + reclaim)

int fd = open("/dev/bigwave", O_RDWR);
for (int i = 0; i < 64; i++) submit_job(fd, regs_buf);   // fill worker queue
submit_job(fd, regs_buf);                                // victim job
auto t0 = now();
while (now() - t0 < 17000ms) sched_yield();              // hit 16s timeout
close(fd);                                               // free inst/job
spray_uds_msgs(payload_pointing_to_target, spray_count); // reclaim slab
sleep(1);                                                // let worker memcpy_fromio
  • regs_buf dovrebbe preconfigurare BigWave per rimanere inattiva (es., impostare i bit di controllo per saltare l’esecuzione) in modo che l’immagine dei registri copiata indietro rimanga deterministica.

Punti chiave per i revisori del driver

  • Gli struct di job inline per-FD messi in coda verso worker async devono mantenere riferimenti che sopravvivano ai percorsi di timeout/cancel; la chiusura di un FD deve essere sincronizzata con il consumo da parte del worker.
  • Qualsiasi helper di copia MMIO (memcpy_fromio/memcpy_toio) che usa puntatori a buffer provenienti da job dovrebbe essere validato o duplicato prima di essere messo in coda per evitare primitive UAF→write.

Riferimenti

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks