# CVE-2022-22265: Samsung NPU device driver double free in Android

Double free in Samsung NPU driver /dev/vertex10 via invalid VS4L_VERTEXIOC_S_FORMAT then STREAM_OFF, exploited in the wild for kernel r/w and LPE.

- Payout: Real-world hack
- Severity: high
- Program: Samsung Android
- Credited: Seonung Jang of STEALIEN
- Disclosed: 2022-01-01
- CVE: CVE-2022-22265
- Write-up quality: 8/10
- Original: https://github.com/googleprojectzero/0days-in-the-wild/blob/main/0day-RCAs/2022/CVE-2022-22265.md
- Library page: https://bugbountylibrary.com/r/p0%3ACVE-2022-22265
- Tags: domain:desktop impact:privesc impact:rce kind:incident platform:project-zero sev:high tech:linux technique:chained technique:incomplete-fix technique:source-review vuln:memory-corruption vuln:privilege-escalation

**Target:** Samsung Exynos NPU kernel driver /dev/vertex10 (vision-buffer.c)
**Root cause:** vb_queue_s_format frees q->format.formats on the __vb_find_format error path but does not NULL the pointer, so vb_queue_stop later kfree()s it again.
**Steps:**
1. Open /dev/vertex10 and initialize the NPU.
2. ioctl `VS4L_VERTEXIOC_S_FORMAT` with a format_list whose format colorspace is invalid so __vb_find_format returns NULL, triggering first kfree(q->format.formats).
3. Reallocate the freed object via `select` syscall to occupy it.
4. ioctl `VS4L_VERTEXIOC_STREAM_OFF` -> npu_vertex_streamoff -> npu_queue_stop -> vb_queue_stop -> kfree(q->format.formats) again (second free).
5. Occupy freed object with pipe_buffer structs via `fcntl(fd, F_SETPIPE_SZ, size)`.
6. Wake the select thread; returned fd bitmasks leak the pipe_buffer kernel object.
7. Spam page tables to reuse the pipe page (KSMA) and overwrite page table via pipe write to get arbitrary r/w.
**How found:** Likely variant analysis of CVE-2020-28343; the in-the-wild exploit sample modified the public PoC for that CVE. Bug existed since S10/Exynos 9820.
**Exploitation:** Attacker in untrusted_app context triggers the double free, uses select to occupy the freed object, frees again via STREAM_OFF, reclaims with pipe_buffer via F_SETPIPE_SZ, leaks pipe_buffer through select fd bitmasks, then performs a Kernel Space Mirroring Attack by spamming page tables to reuse the leaked pipe page and overwriting the page table through the pipe, yielding arbitrary kernel read/write and local privilege escalation.
**Escalation:** Double free used first as kernel info leak, then chained into KSMA to convert into arbitrary kernel r/w primitive and LPE.
**Insight:** Audit error-handling paths in ioctl handlers where a heap pointer is kfree()'d but not NULLed, then freed again during queue/stream teardown; fuzz all ioctl calls with invalid arguments to hit these paths.
