pagecache_write_begin() stores shmem ERR_PTR in *pagep and returns success, causing kmap panic
Summary
pagecache_write_begin() calls shmem_read_mapping_page(obj OFF_TO_IDX(pos)) unconditionally writes result into *pagep then returns 0 (linux_shmem.c:102-104). shmem_read_mapping_page can fail ERR_PTR(-ENOMEM) on memory pressure (also leaks VM object lock per DF-2165). Function never checks IS_ERR(). i915 caller i915_gem.c:6488-6492 checks if(err<0) goto fail but err always 0 proceeds to kmap(page) with page=ERR_PTR(-ENOMEM)=0xfffffffffffffff4. kmap (highmem.h:49-52) does PHYS_TO_DMAP(VM_PAGE_TO_PHYS((struct vm_page*)pg)) reading phys_addr at 0xfffffffffffffff4+offsetof(phys_addr) unmapped kernel address page-faults panicking. Reachable: unprivileged video-group user drives OOM triggers shmem-backed GEM writes via i915_gem_object_create_from_data (context creation execbuffer batches). On OOM kernel takes fatal page fault in DMAP region panics entire system.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2166 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | source-level analysis with path:line citations | 1.8 KB | β raw |
| reachability.txt | environment | guest PCI/device survey proving no required HW | 1.6 KB | view raw |
| fix.diff | suggested-fix | git-apply-able fix (validated: applies clean) | 519 B | view raw |
| build.sh | build-log | documents HW requirement | 550 B | view raw |
| run.sh | run-log | documents HW requirement | 272 B | view raw |
| env.txt | environment | guest uname and environment | 491 B | view raw |
DF-2166: pagecache_write_begin() stores shmem ERR_PTR in *pagep, causes kmap panic
Verdict: NOT REPRODUCED (HW-gated) β source-confirmed real bug
Reachability
NOT reachable on this QEMU guest. pagecache_write_begin() is in
sys/dev/drm/linux_shmem.c, part of drm.ko. Called from DRM GEM write paths.
Without GPU hardware, unreachable.
Mechanism (source-confirmed)
pagecache_write_begin() at linux_shmem.c:98-105:
int
pagecache_write_begin(struct vm_object *obj, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata)
{
*pagep = shmem_read_mapping_page(obj, OFF_TO_IDX(pos));
return 0;
}
shmem_read_mapping_page() returns ERR_PTR(-ENOMEM) on failure (lines 57, 60, 70, 73).
The result is stored directly into *pagep without checking IS_ERR(), and the
function returns 0 (success).
The caller (typically i915 GEM write path) then dereferences *pagep via kmap(*pagep)
or page_address(*pagep). Since *pagep contains the error value (e.g. (void*)-ENOMEM
= 0xFFFFFFFFFFFFFFEA), this causes a kernel panic (invalid page address) or
arbitrary memory access.
This compounds with DF-2165: the same error paths also leak the VM object lock.
Primitive
- Class: unchecked error β invalid pointer dereference β panic/arbitrary access
- The error pointer
0xFFFFFFFFFFFFFFEAis used as astruct page *β page fault - On non-INVARIANTS kernels: may access arbitrary kernel memory at high addresses
Fix
fix.diff: Check IS_ERR() on the return of shmem_read_mapping_page() and propagate
the error instead of returning 0:
struct page *page = shmem_read_mapping_page(obj, OFF_TO_IDX(pos));
if (IS_ERR(page))
return PTR_ERR(page);
*pagep = page;
return 0;
Fix verification
not_testablegit apply --check clean
git apply --check clean
Confirmed kernel references
β
Detail
Exploit chain
none (HW-gated)
Evidence (decisive lines)
HW-GATED (no GPU). Source-confirmed: pagecache_write_begin stores ERR_PTR in *pagep then returns 0, caller derefs as page* -> panic.
Verified recommended fix
HW-GATED (no GPU). Source-confirmed: pagecache_write_begin stores ERR_PTR in pagep then returns 0, caller derefs as page -> panic.
Verdict
HW-GATED (no GPU). Source-confirmed: pagecache_write_begin stores ERR_PTR in pagep then returns 0, caller derefs as page -> panic.
No comments yet.