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

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

TL;DR

  • From the SELinux-confined mediacodec context, /dev/bigwave (Pixel AV1 hardware accelerator) is reachable. A backlog of jobs makes BIGO_IOCX_PROCESS hit its 16s wait_for_completion_timeout() and return while the worker thread concurrently dequeues the same inline job structure.
  • Closing the FD immediately frees struct bigo_inst (which embeds struct bigo_job). The worker reconstructs inst = container_of(job, ...) and later uses freed fields such as job->regs inside bigo_run_job(), yielding a Use-After-Free on the inline job/inst.
  • bigo_pull_regs(core, job->regs) performs memcpy_fromio(regs, core->base, core->regs_size). By reclaiming the freed slab and overwriting job->regs, an attacker gets a ~2144-byte arbitrary kernel write to a chosen address, with partial control of the bytes by pre-programming register values before the timeout.

Attack surface mapping (SELinux → /dev reachability)

  • Use tools like DriverCartographer to enumerate device nodes accessible from a given SELinux domain. Despite mediacodec’s constrained policy (software decoders should stay in an isolated context), /dev/bigwave remained reachable, exposing a large attack surface to post-media-RCE code.

Vulnerability: BIGO_IOCX_PROCESS timeout vs worker

  • Flow: ioctl copies user register buffer into job->regs, queues the inline job, then wait_for_completion_timeout(..., 16s). On timeout it tries to dequeue/cancel and returns to userspace.
  • Meanwhile bigo_worker_thread may have just dequeued the same 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;
  • タイムアウト後に userspace が FD を閉じると、inst/job が解放される一方で worker はそれらを使い続ける → UAF。FD のライフタイムが worker スレッドの job ポインタと同期していない。

Exploitation outline

  1. バックログ + タイムアウト: worker が遅延するように十分な job をキューし、BIGO_IOCX_PROCESS を発行して 16s のタイムアウト経路に到達させる。
  2. 使用中に解放: ioctl が戻るとすぐに close(fd) を呼び、worker がまだデキューした job を実行している間に inst/job を解放する。
  3. 再確保 + ポインタ制御: リクレーマをスプレー(例: Unix domain socket message の割り当て)して解放された slab スロットを占有し、inline の job、特に job->regs を上書きする。
  4. 任意書き込み: bigo_pull_regs() 実行時に memcpy_fromio() が MMIO から core->regs_size (~2144 bytes)job->regs の攻撃者指定アドレスへ書き込み、KASLR リークなしで大きな write-what-where を生成する。
  5. データ成形: レジスタは最初にユーザデータからプログラムされる(bigo_push_regs)ため、ハードウェアが実行しないように設定し、コピーバックされたレジスタイメージが攻撃者制御のバイトに近いままにする。

Takeaways for driver reviewers

  • async workers にエンキューされる inline の per-FD job 構造体は、timeout/cancel 経路を乗り越える参照を保持している必要がある;FD を閉じる操作は worker の消費と同期しなければならない
  • job から取ったバッファポインタを使う MMIO コピー補助(memcpy_fromio/memcpy_toio)は、enqueuing 前に検証または複製されるべきで、UAF→write プリミティブを防ぐ。

References

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする