# CVE-2023-33107: Qualcomm Adreno GPU KGSL_IOCTL_GPUOBJ_IMPORT integer overflow

Integer overflow in Qualcomm Adreno KGSL IOMMU SVM region overlap check lets a racing mmap insert a bogus rbtree entry, yielding dangling IOMMU PTEs and kernel R/W.

- Payout: Real-world hack
- Severity: high
- Program: Qualcomm Adreno GPU
- Credited: Benoît Sevens and Jann Horn
- Disclosed: 2023-10-02
- CVE: CVE-2023-33107
- Write-up quality: 10/10
- Original: https://github.com/googleprojectzero/0days-in-the-wild/blob/main/0day-RCAs/2023/CVE-2023-33107.md
- Library page: https://bugbountylibrary.com/r/p0%3ACVE-2023-33107
- Tags: domain:mobile impact:privesc impact:rce kind:incident platform:project-zero sev:high tech:linux technique:incomplete-fix technique:race-window technique:source-review vuln:memory-corruption vuln:race-condition

**Target:** Linux kernel msm KGSL driver (kgsl_iommu_set_svm_region / IOCTL_KGSL_GPUOBJ_IMPORT, IOCTL_KGSL_MAP_USER_MEM)
**Root cause:** iommu_addr_in_svm_ranges() and the overlap check in kgsl_iommu_set_svm_region() compute gpuaddr+size without detecting wrap-around, so a user-supplied address/size pair with end<start passes validation and is inserted into the IOMMU rbtree.
**Steps:**
1. Allocate UAF and OVERLAP GPU objects via `IOCTL_KGSL_GPUOBJ_ALLOC` and `mmap()` UAF (0x7001ff000, size 0x10004000) to populate IOMMU PTEs and rbtree.
2. `munmap()` UAF (rbtree entry and PTEs persist), then `mmap()` a small anon VMA at BOGUS start 0x700204000.
3. Allocate and `mmap()` PLACEHOLDER (0x710204000, size 0x10400000).
4. In a racing thread call `IOCTL_KGSL_MAP_USER_MEM` with gpuaddr=0x700204000 and size=0xffffffffffefd000 so gpuaddr+size wraps; BOGUS entry inserted into rbtree.
5. In main thread `mmap()` OVERLAP (0x7001fe000, size 0x7000); bogus BOGUS entry causes overlap with UAF to be missed and OVERLAP inserted.
6. arm_lpae_map_sg() calls arm_lpae_init_pte() for 0x7001ff000 without checking return, increments num_pte, then bails; arm_smmu_unmap() deletes PTEs at 0x7001fe000 and 0x7001ff000, zeroing UAF's first PTE.
7. Free UAF via `IOCTL_KGSL_GPUOBJ_FREE`; __arm_lpae_unmap() bails at zeroed first PTE, leaving dangling IOMMU PTEs while physical pages are freed.
8. Invoke shrinker to return freed KGSL pages to page allocator, spray task_structs into them.
9. Use `IOCTL_KGSL_GPU_COMMAND` to read/write via dangling PTEs: scan for task_struct, overwrite addr_limit with KERNEL_DS.
**How found:** iommu_addr_in_svm_ranges() was introduced in the fix for CVE-2020-11261; auditing that same code area for variants of the earlier bug would reveal the missing wrap-around check.
**Exploitation:** Race between IOCTL_KGSL_MAP_USER_MEM (wrapping BOGUS range) and mmap of OVERLAP corrupts the IOMMU rbtree so an overlapping range is accepted; unchecked arm_lpae_init_pte() failure plus unmap bailout zeroes the UAF object's first PTE, so freeing UAF leaves dangling IOMMU PTEs. Shrinker returns pages to the allocator, task_structs are sprayed in, and GPU commands read/write those pages to overwrite addr_limit with KERNEL_DS for kernel access.
**Escalation:** Dangling IOMMU PTEs give GPU read/write over freed pages reused as task_struct; overwriting addr_limit to KERNEL_DS yields kernel arbitrary read/write.
**Insight:** When a prior CVE fix adds a range-validation helper, audit that helper for arithmetic wrap: check whether start+size can overflow and whether end<start is rejected, especially where the range is later inserted into an interval tree used for overlap decisions.
