DF-4507 / verdict.json
{ "finding_id": "DF-4507", "status": "untested", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Runtime-untestable on the audit guest (QEMU std-VGA, no drm driver attaches, so the TTM pools are never instantiated), but the defect is certain from static proof reproduced by static_proof.sh: the pool shrinker callbacks are assigned to manager->mm_shrink yet register_shrinker() has no definition anywhere in sys/ (its only call sites are #if 0 or whole-file-preprocessed-out), and the fallback EVENTHANDLER_REGISTER(vm_lowmem, ttm_pool_shrink_scan, ...) creates a slow-handler list that no EVENTHANDLER_INVOKE(vm_lowmem) site in the kernel ever fires. Consequence: on drm-attached systems the WC/UC page pools are never drained under memory pressure and are bounded only by the put-path trim at options.max_size (half the kernel zone, per pool \u2014 ttm_memory.c:353), turning reclaimable memory into avoidable OOM kills. Assessed impact class: local memory-pressure DoS amplification (dos), Medium. The registered callback also has a mismatched signature (vm_lowmem handlers are func(void*,int) while ttm_pool_shrink_scan dereferences its second arg as struct shrink_control* at lines 398/418), a panic landmine if the event is ever wired naively; fix.diff adds the typed adapter plus the event declaration and pageout invoke site.", "exploit_chain": "", "evidence": "static_proof.log sections [1]-[6]: vm_lowmem referenced only by ttm_page_alloc.c:447,453; full EVENTHANDLER_INVOKE enumeration shows COUNT=0 for vm_lowmem; register_shrinker absent (i915 call #if 0 at i915_gem_shrinker.c:523-531, dma variant preprocessed out at ttm_page_alloc_dma.c:36); ttm_page_alloc.c unguarded/live; only live trim at ttm_page_alloc.c:709-721 vs ttm_memory.c:353; env.txt documents guest lacking GPU (chip=0x11111234, no /dev/dri) and the kldload-drm linker wedge that forced a guest reset", "kernel_refs": [ "sys/dev/drm/ttm/ttm_page_alloc.c:385", "sys/dev/drm/ttm/ttm_page_alloc.c:397", "sys/dev/drm/ttm/ttm_page_alloc.c:418", "sys/dev/drm/ttm/ttm_page_alloc.c:442", "sys/dev/drm/ttm/ttm_page_alloc.c:447", "sys/dev/drm/ttm/ttm_page_alloc.c:709", "sys/dev/drm/include/linux/shrinker.h:32", "sys/dev/drm/i915/i915_gem_shrinker.c:525", "sys/dev/drm/ttm/ttm_page_alloc_dma.c:36", "sys/dev/drm/ttm/ttm_memory.c:353", "sys/sys/eventhandler.h:114", "sys/sys/eventhandler.h:128" ], "poc_changes": "n/a \u2014 no runtime PoC was seeded; a static proof script (static_proof.sh) was authored instead and its full output captured in static_proof.log", "attempts": 0, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 900, "guest_dirty": 0, "build_cmd": "n/a (static-analysis finding; run ./static_proof.sh from repo root)", "run_cmd": "./static_proof.sh > static_proof.log", "code_hash": "dc0f2bda8bdf90bdc74044c980364e6f0f6cc63bf064641bef6cdeffb5da0bca", "notes": "Guest session facts: no GPU (/dev/dri absent, QEMU std VGA 1234:1111) so pools never instantiate -> finding untestable there, hence status untested with certainty established statically. Side observation recorded in env.txt: kldload drm wedges the guest kernel linker lock (kldstat blocks in D on kldlk) via the MODULE_DEPEND(drm, agp) load path \u2014 outside both audited files; guest reset clean (vm.sh reset with-src, verified up) so guest_dirty=0. DF-1663 (known pass-1 fini race) is NOT re-reported; its racing counterpart is this same dead shrinker, so it is practically untriggerable on this tree.", "recommended_fix": "Declare vm_lowmem with a real handler type in sys/sys/eventhandler.h, invoke it from the page daemons catastrophic-shortage block in sys/vm/vm_pageout.c, and register a typed adapter (ttm_pool_lowmem(void*,int) building a local struct shrink_control) instead of casting ttm_pool_shrink_scan; drop the dead mm_shrink assignments", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff (a35e872c...) proposes the correct wiring (event typedef+declare, pageout invoke before OOM kills, typed adapter replacing the signature-mismatched registration). Validation requires reproducing the baseline first, which needs a GPU-attached system this guest lacks; additionally the adapter removes the latent near-NULL sc->gfp_mask write that naive wiring would introduce", "fix_evidence": "findings/poc/DF-4507/fix.diff hunks 1-3; landmine lines ttm_page_alloc.c:398,418; invoke-site placement sys/vm/vm_pageout.c:1794ff catastrophic block" } |