β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-2166

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2166 Β· 6 files
FileTypeDescriptionSize
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
VERDICT.md verdict source-level analysis with path:line citations
↓ download 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 0xFFFFFFFFFFFFFFEA is used as a struct 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_testable
baseline no→ patch + rebuild →patched clean

git 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.