Pixel BigWave BIGO timeout race UAF → gravação de 2KB no kernel a partir de mediacodec

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks

TL;DR

  • A partir do contexto confinado pelo SELinux mediacodec, /dev/bigwave (acelerador de hardware Pixel AV1) é alcançável. Um backlog de jobs faz com que BIGO_IOCX_PROCESS atinja seu 16s wait_for_completion_timeout() e retorne enquanto a worker thread simultaneamente faz dequeue da mesma estrutura inline job.
  • Fechar o FD imediatamente libera struct bigo_inst (que embute struct bigo_job). O worker reconstrói inst = container_of(job, ...) e depois usa campos já liberados como job->regs dentro de bigo_run_job(), resultando em um Use-After-Free no job/inst inline.
  • bigo_pull_regs(core, job->regs) faz memcpy_fromio(regs, core->base, core->regs_size). Ao reusar o slab liberado e sobrescrever job->regs, um atacante obtém uma gravação arbitrária no kernel de ~2144 bytes para um endereço escolhido, com controle parcial dos bytes ao pré-programar valores de registradores antes do timeout.
  • Rastreado como CVE-2025-36934; corrigido nas builds 2026-01-05 Pixel/2025-12-01 ASB.

Mapeamento da superfície de ataque (SELinux → /dev reachability)

  • Use ferramentas como DriverCartographer para enumerar nodes de dispositivo acessíveis a partir de um domínio SELinux. Apesar da política restrita do mediacodec (decoders em software deveriam ficar em um contexto isolado), /dev/bigwave permaneceu acessível, expondo uma grande superfície de ataque para código com post-media-RCE.

Vulnerabilidade: BIGO_IOCX_PROCESS timeout vs worker

  • Fluxo: ioctl copia o buffer de registradores do usuário para job->regs, enfileira o job inline, então wait_for_completion_timeout(..., 16s) é chamado. No timeout ele tenta fazer dequeue/cancel e retorna para userspace.
  • Enquanto isso, bigo_worker_thread pode ter acabado de fazer dequeue do mesmo 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 o userspace fechar o FD após o timeout, inst/job são liberados enquanto o worker continua a usá-los → UAF. Não existe sincronização que vincule a duração de vida do FD ao ponteiro job do worker thread.

Esquema de exploração

  1. Backlog + timeout: Queue enough jobs so the worker is delayed, then issue BIGO_IOCX_PROCESS and let it hit the 16s timeout path.
  2. Free while in use: As soon as ioctl returns, close(fd) to free inst/job while the worker is still running the dequeued job.
  3. Reclaim + pointer control: Spray reclaimers (e.g., Unix domain socket message allocations) to occupy the freed slab slot and overwrite the inline job, especially job->regs.
  4. Arbitrary write: When bigo_pull_regs() runs, memcpy_fromio() writes core->regs_size (~2144 bytes) from MMIO into the attacker-supplied address in job->regs, producing a large write-what-where without a KASLR leak.
  5. Data shaping: Because registers are first programmed from user data (bigo_push_regs), set them so the hardware does not execute, keeping the copied-back register image close to attacker-controlled bytes.

Esqueleto mínimo de PoC (blocking backlog + 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 deve pré-configurar o BigWave para ocioso (por exemplo, definir bits de controle para pular a execução) para que a imagem de registradores copiada de volta permaneça determinística.

Principais conclusões para revisores do driver

  • As estruturas de job inline por-FD enfileiradas em workers assíncronos devem manter referências que sobrevivam aos caminhos de timeout/cancelamento; fechar um FD deve sincronizar com o consumo pelo worker.
  • Qualquer helper de cópia MMIO (memcpy_fromio/memcpy_toio) que use ponteiros de buffer provenientes de jobs deve ser validado ou duplicado antes de enfileirar para evitar primitivos UAF→write.

Referências

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks