Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,58 @@ sleep(1); // let worker memcpy_fr

- `regs_buf` should preconfigure BigWave to idle (e.g., set control bits to skip execution) so the copied-back register image stays deterministic.


## Related successor primitive on Pixel 10: unbounded `/dev/vpu` `mmap()` → physical-memory R/W

Project Zero's Pixel 10 follow-up replaced BigWave with another **mediacodec-reachable** driver: `/dev/vpu` for the **Chips&Media Wave677DV** decoder. The bug class is even shallower: the driver intends to expose only the VPU MMIO CSR window, but its `mmap` handler trusts the attacker-controlled VMA length.

```c
static int vpu_mmap(struct file *fp, struct vm_area_struct *vm)
{
...
pfn = core->paddr >> PAGE_SHIFT;
return remap_pfn_range(vm, vm->vm_start, pfn,
vm->vm_end - vm->vm_start,
vm->vm_page_prot) ? -EAGAIN : 0;
}
```

### Why this is exploitable

- `pfn` is fixed to the VPU MMIO physical base (`core->paddr >> PAGE_SHIFT`).
- The mapped length is **`vm->vm_end - vm->vm_start`**, i.e. the user-requested `mmap()` size.
- There is **no check** that the requested size is bounded by the real MMIO resource length.

Therefore, if `/dev/vpu` is reachable from a compromised app/service domain, a large `mmap()` does not stop at the register window: it keeps mapping the **contiguous physical pages after the VPU MMIO range** into userspace.

### Exploitation model

1. Gain code execution in a context allowed to open `/dev/vpu` (for example **mediacodec** after a media-parser bug).
2. `open("/dev/vpu", O_RDWR)`.
3. `mmap()` a region much larger than the real CSR/MMIO window.
4. Compute the offset from the returned mapping to the kernel physical base.
5. Read or overwrite kernel `.text`, `.data`, credentials, function pointers, or build a more convenient arbitrary R/W primitive.

Representative pattern:

```c
int fd = open("/dev/vpu", O_RDWR);
void *map = mmap(NULL, HUGE_LEN, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
uint8_t *kbase = (uint8_t *)map + (KERNEL_PHYS_BASE - VPU_PHYS_BASE);
// Direct kernel physical read/write via kbase[...]
```

### Practical notes

- On Pixels, this primitive is especially strong because the kernel physical placement has been observed to be predictable; see also:

{{#ref}}
arm64-static-linear-map-kaslr-bypass.md
{{#endref}}

- Compared with the earlier BigWave UAF, this bug skips heap feng shui almost entirely: once the oversized mapping succeeds, the attacker gets **direct userspace access to kernel physical memory**.
- Review pattern: any driver that exposes MMIO via `remap_pfn_range()` must clamp `requested_len <= resource_size`, align offsets carefully, and reject arbitrary expansion beyond the device BAR/resource.

## Takeaways for driver reviewers

- Inline per-FD job structs enqueued to async workers must hold references that survive timeout/cancel paths; **closing an FD must synchronize with worker consumption**.
Expand All @@ -61,5 +113,7 @@ sleep(1); // let worker memcpy_fr
- [Pixel 0-click (Part 2): Escaping the mediacodec sandbox via the BigWave driver](https://projectzero.google/2026/01/pixel-0-click-part-2.html)
- [Project Zero issue 426567975 – BigWave BIGO timeout UAF](https://project-zero.issues.chromium.org/issues/426567975)
- [CVE-2025-36934 entry (BigWave driver)](https://www.cybersecurity-help.cz/vulnerabilities/119071/)
- [Project Zero – Pixel 10 Zero-Click-to-Root: Dolby CVE-2025-54957 and /dev/vpu Kernel mmap Privilege Escalation](https://projectzero.google/2026/05/pixel-10-exploit.html)
- [Project Zero issue 463438263 – /dev/vpu unbounded mmap](https://project-zero.issues.chromium.org/issues/463438263)

{{#include ../../banners/hacktricks-training.md}}