DF-5647 / verdict.json
{ "finding_id": "DF-5647", "status": "reproduced", "verdict": "Negative hint values (portsize/msize = -1 with positive base, or port/maddr = -1 with positive size) pass isahint.c:63/70s start>0||count>0 guard; isa_set_resource then stores rle entries with sign-extended UINT64_MAX start/count and wrapped end = start+count-1 < start. Live-verified in guest kernel memory via isa_probe_nomatch prints: atkbdc1 port 0x60-0x5e, wbsio0 port 0x2e-0x2c, lm0 iomem 0xd0000-0xcfffe and port 0xffffffffffffffff-0xe (inverted ranges), against clean controls (wbsio1 0x4e-0x4f, it0-3). The atkbdc1 line proves rman GRANTED the inverted region: rid1 (0x64) is only added after the rid0 default alloc returned non-NULL, i.e. rman_reserve_resource(0x60,0x5e,2^64-1) succeeded via subr_rman.c:236-238s wrap-satisfying (rend-rstart+1)>=count and double-claimed port 0x60 already allocated to atkbdc0. Persistent poisoned rle (lm0 iomem) plus transient rman free-list corruption (duplicated boundary byte, unsorted list) per subr_rman.c:276-291. Bookkeeping/hardware-claim corruption inside properly-allocated structures \u2014 no adjacent-object memory-safety violation demonstrated. Root/loader-gated: Low severity.", "reproduced": true, "impact": "kernel resource bookkeeping corruption (inverted rle/rman ranges, overlapping/double-claimed I/O ports)", "confidence": "certain", "exploit_chain": "loader.conf.local negative hints -> resource_kenv strtol (no range check, kenv overrides compiled devtab) -> isahint_add_device guard misses negative count/start -> bus_set_resource -> isa_set_resource end=start+count-1 wraps (isa_common.c:910) -> poisoned rle persists in child idev->id_resources -> on any default-range alloc, resource_list_allocs count=ulmax(count,rle->count) (subr_bus.c:2698-2701) feeds 2^64-1 into rman_reserve_resource -> inverted region granted, split-in-three duplicates the boundary byte into two free regions and breaks list ordering (subr_rman.c:276-291); allocations can overlap already-claimed ports (atkbdc1 over atkbdc0s 0x60).", "evidence": "run.log (full verbose dmesg of the poisoned boot; decisive lines: atkbdc1 ... port 0x60-0x5e,0x64, lm0 ... port 0xffffffffffffffff-0xe iomem 0xd0000-0xcfffe, wbsio0 ... 0x2e-0x2c vs controls wbsio1 ... 0x4e-0x4f, it0-3); run.fixed.log (patched kernel: poisoned devices print bare failed to probe on isa1, controls unchanged); VERDICT.md (full math + negative results)", "kernel_refs": [ "sys/bus/isa/isahint.c:59-64", "sys/bus/isa/isahint.c:66-71", "sys/kern/subr_bus.c:2306-2326", "sys/bus/isa/isa_common.c:909-911", "sys/kern/subr_bus.c:2693-2701", "sys/kern/subr_rman.c:224-238", "sys/kern/subr_rman.c:266-291" ], "poc_changes": "Replaced seeded idea with loader.conf kenv hints (proven pattern): the isahint value path only reads kenv for COMPILED-IN devtab names (atkbdc/lm/wbsio/it/sio/adv/vga in X86_64_GENERIC), so the hints target those names; boot_verbose=YES added so isa_probe_nomatch prints the live rle ranges.", "attempts": 2, "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": 160, "guest_dirty": 0, "build_cmd": "none (loader.conf kenv hint trigger; see trigger.hints / run.sh)", "run_cmd": "cp trigger.hints /boot/loader.conf.local && shutdown -r now && dmesg | grep failed to probe", "code_hash": "b0ecd14ce7f323a1896772ebfc26ce8494533d3992256bf5895ffd1dd57e9a57", "notes": "Reproduced identically on two independent boots (one after a full vm.sh reset). Guest isahint children exist but are invisible in plain devinfo (unattached, dd_state < DS_INPROGRESS; use devinfo -v). sio unit renumbering on this guest (ACPI sio0 pre-empts unit 0, isahint children shift +1) explains historical cant drain lines; no disable-bypass bug. Guest reset to clean-source snapshot after verification.", "recommended_fix": "Reject negative geometry at isahint.c:63/70: require start >= 0 && count >= 0 in addition to the existing start>0||count>0 (keeps compiled port-only hints with count=0 working).", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "Same fix.diff as DF-5646 (shared isahint.c patch, kernel #1 Fri Oct 9, BUILD_OK): reboot with the identical poison set armed shows bare failed to probe on isa1 for atkbdc1/lm0/wbsio0 (no ranges stored) while compiled hints still work (wbsio1 0x4e-0x4f, it0-3, sio 0x3f8/0x2f8-0x2ff) \u2014 inverted ranges gone, no regression.", "fix_evidence": "run.fixed.log (patched-kernel current-boot dmesg segment); build.log (kernel build + installkernel + BUILD_OK tail); diff in fix.diff" } |