DF-5162 / verdict.json
{ "finding_id": "DF-5162", "status": "not_reproduced", "reproduced": false, "impact": "none", "confidence": "certain", "verdict": "Source-proven use-after-free of the bktr_mem stored-address registry: the unprivileged METEORSETGEO grow path (bktr_core.c:1667-1673) frees the attach-time frame buffer without re-storing BKTR_MEM_BUF, the registry has no invalidation mechanism (bktr_mem.c:103-138 only ever sets addresses_stored=1), and the unload/reload design that detach relies on (bktr_os.c:362-364) reinstalls the freed KVA at reload (bktr_core.c:382-390) where bktr_core.c:429-432 immediately bzeros ~3.5 MB of possibly-reallocated kernel KVA and later DMAs video into it. Not reproduced on the audit guest because no Bt848/Bt878 PCI device exists there (env.txt: NO_BT8XX_PCI_DEVICE, /dev/bktr0 ENOENT in run.log); the trigger builds cleanly. Full unpriv-to-root escalation is NOT claimed: completing the chain requires a root kldunload/kldload of bktr.ko between the plant and the harvest, hence Low severity.", "exploit_chain": "unpriv: open /dev/bktr0 (mode 0444, bktr_os.c:325) -> METEORSETGEO rows=1024 cols=1024 frames=2 RGB16 (1026 pages > 868 default) -> grow path kmem_free()s original bigbuf, installs new buffer, registry keeps freed KVA with addresses_stored=1; root: kldunload bktr && kldload bktr -> common_bktr_attach retrieves stale KVA -> bktr_core.c:432 bzero(freed,3.5MB) + read()/mmap()/RISC-DMA target freed range -> corruption of whatever kernel objects were reallocated there. Chain needs root mid-way (driver reload), so impact is corruption-on-admin-action, not unpriv privesc.", "evidence": "VERDICT.md (full line-cited chain); run.log (guest: BUILD_OK then open(/dev/bktr0): ENOENT \u2014 hardware-gated); env.txt (no Brooktree PCI device, modules present); fix.diff (re-store after grow; git apply --check clean)", "kernel_refs": [ "sys/dev/video/bktr/bktr_mem.c:103", "sys/dev/video/bktr/bktr_mem.c:115", "sys/dev/video/bktr/bktr_mem.c:142", "sys/dev/video/bktr/bktr_core.c:415", "sys/dev/video/bktr/bktr_core.c:382", "sys/dev/video/bktr/bktr_core.c:1667", "sys/dev/video/bktr/bktr_core.c:1669", "sys/dev/video/bktr/bktr_core.c:429", "sys/dev/video/bktr/bktr_core.c:432", "sys/dev/video/bktr/bktr_os.c:325", "sys/dev/video/bktr/bktr_os.c:362" ], "poc_changes": "no orchestrator seed existed for this ID; trigger authored fresh in this pack (ioctl numbers/struct mirrored from sys/dev/video/meteor/ioctl_meteor.h:47-52,72)", "attempts": 1, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026\troot@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 45, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o grow_stale grow_stale.c", "run_cmd": "./run.sh (then, on hardware, root: sh reload_stale.sh)", "code_hash": "ab3e3a9c7292a48ca52e6020e275cb3f67653bb0eb0032805ec22bc2e0090679", "notes": "Hardware-gated on the audit QEMU guest (no Bt848 card; /dev/bktr0 absent) \u2014 consistent with pass-1 context no bktr on guest. Distinct from DF-4671/4672/4673 (same grow path, different defects: mmap fault race, wired-page leak, unzeroed pages) and DF-3789 (frames=0 guard skip): none covers the bktr_mem registry staleness across module reload. Guest /tmp artifacts removed after the attempt.", "recommended_fix": "Re-store the live bigbuf in the METEORSETGEO grow path: bktr_store_address(unit, BKTR_MEM_BUF, bktr->bigbuf) after the if/else at bktr_core.c:1678-1681 (see fix.diff); longer term give bktr_mem an invalidate API.", "fix_status": "not_testable", "fix_baseline_reproduced": false, "fix_patched_reproduced": false, "fix_verdict": "Fix validation not testable on this guest: the baseline itself cannot reproduce (no Bt848 hardware -> common_bktr_attach never runs), so a patched kernel cannot be differentially exercised. fix.diff is source-verified (git apply --check clean) and provable by inspection: after it, memory_list[unit].buf always equals the live bktr->bigbuf at every point the registry is consulted.", "fix_evidence": "fix.diff; VERDICT.md Fix section; git apply --check output APPLIES_CLEAN recorded in the audit trail" } |