# CVE-2022-22706 / CVE-2021-39793: Mali GPU driver makes read-only imported pages host-writable

Mali GPU driver's kbase_jd_user_buf_pin_pages ignored KBASE_REG_CPU_WR when pinning imported user pages, letting attackers write into read-only shared-library pages.

- Payout: Real-world hack
- Severity: high
- Program: Arm Mali GPU driver for Linux/Android
- Credited: Jann Horn
- Disclosed: 2022-03-07
- CVE: CVE-2021-39793
- Write-up quality: 8/10
- Original: https://github.com/googleprojectzero/0days-in-the-wild/blob/main/0day-RCAs/2021/CVE-2021-39793.md
- Library page: https://bugbountylibrary.com/r/p0%3ACVE-2021-39793
- Tags: domain:mobile domain:oss impact:integrity impact:privesc kind:incident platform:project-zero sev:high tech:android tech:linux technique:incomplete-fix technique:source-review vuln:access-control vuln:privilege-escalation

**Target:** Mali GPU kernel driver ioctl (KBASE_MEM_TYPE_IMPORTED_USER_BUF)
**Root cause:** kbase_jd_user_buf_pin_pages() only checked KBASE_REG_GPU_WR to decide FOLL_WRITE for pin_user_pages_remote(), ignoring KBASE_REG_CPU_WR, so read-only pages were pinned writable.
**Steps:**
1. Map a page from a shared library read-only in userspace.
2. Create a Mali KBASE_MEM_TYPE_IMPORTED_USER_BUF memory object with KBASE_REG_CPU_WR set but KBASE_REG_GPU_WR clear, avoiding KBASE_REG_SHARE_BOTH.
3. Trigger kbase_jd_user_buf_pin_pages() via `KBASE_IOCTL_KCPU_QUEUE_ENQUEUE` with `BASE_KCPU_COMMAND_TYPE_MAP_IMPORT`, or submit an atom with `BASE_JD_REQ_EXTERNAL_RESOURCES`.
4. Write into the Mali memory object from host userspace, modifying the read-only page.
**How found:** Variant analysis of the CVE-2021-28664 fix: that patch added a combined CPU_WR|GPU_WR check to one get_user_pages() caller; Horn searched for other get_user_pages() callers in the Mali driver and found the duplicated pin-at-later-time path still only checked GPU_WR.
**Exploitation:** Attacker pins a read-only page (e.g. shared library code) writable via the flawed get_user_pages call, then writes through the Mali memory object's host VMA to corrupt read-only memory, enabling code injection into shared libraries.
**Insight:** When a fix patches one of several duplicated get_user_pages()/pin callers, grep for every other caller of the same primitive and check each one's FOLL_WRITE decision against all relevant permission flags (CPU_WR vs GPU_WR), not just the one the original bug used.
