DF-5641 / verdict.json
{ "finding_id": "DF-5641", "status": "reproduced", "verdict": "isa_alloc_resource()/isa_release_resource() (sys/bus/isa/x86_64/isa.c:87-88,130-131) cast the childs ivars to struct isa_device via DEVTOISA() unconditionally \u2014 including passthrough (grandchild) requests whose ivars belong to a sub-bus (e.g. atkbdc_device_t for psm0 on an ISA-attached atkbdc0) or are NULL \u2014 producing a type-confused/NULL resource-list pointer that is passed into resource_list_alloc()/resource_list_release(). Demonstrated live on the audit guest: with atkbdc0 hinted onto the ISA bus, psm0s psmattach() (psm.c:2014) allocation walked psm->atkbdc(bus_generic_alloc_resource)->isa_alloc_resource with passthrough=1 and a type-confused rl, and succeeded only because both helpers early-forward on passthrough without touching rl (subr_bus.c:2683-2687, 2726-2732). No dereference of the confused pointer exists on any reachable path today, so impact is none; the hazard is one refactor away (hoisting resource_list_find out of the !passthrough guard, as pre-fix FreeBSD once had, turns every ISA PS/2-mouse boot into a NULL/wild deref). Fix: compute rl only for direct children (fix.diff), or restructure FreeBSD-style via BUS_GET_RESOURCE_LIST plus an isa bus_get_resource_list method (DFs generic default returns NULL \u2014 subr_bus.c:3000-3004 \u2014 so the isa method is required).", "reproduced": true, "impact": "none", "confidence": "certain", "exploit_chain": "", "evidence": "run.log [2]-[5] and VERDICT.md: devinfo.hinted.txt shows nexus0->legacy0->pcib0->pci0->isab0->isa0->atkbdc0->psm0 (psm0 = isa grandchild with atkbdc_isa.c:231-232 atkbdc_device_t ivars); dmesg.hinted.txt psm0: <PS/2 Mouse> irq 12 on atkbdc0; env.txt vmstat -i lists psm0 as a registered interrupt (chain through isa.c:76-124 completed); guest stayed up \u2014 proving the type-confused rl at isa.c:87 was computed and never dereferenced (subr_bus.c:2683 early-forward). Guest restored afterwards (acpi0 back).", "kernel_refs": [ "sys/bus/isa/x86_64/isa.c:85-88", "sys/bus/isa/x86_64/isa.c:122-123", "sys/bus/isa/x86_64/isa.c:130-133", "sys/kern/subr_bus.c:2680-2687", "sys/kern/subr_bus.c:2726-2732", "sys/kern/subr_bus.c:3295-3308", "sys/bus/isa/isa_common.h:53-64", "sys/bus/isa/isa_common.c:527-533", "sys/dev/misc/atkbdc_layer/atkbdc_isa.c:83", "sys/dev/misc/atkbdc_layer/atkbdc_isa.c:218-232", "sys/dev/misc/atkbdc_layer/atkbdc_isa.c:290-295", "sys/dev/misc/atkbdc_layer/atkbdc_isa.c:401", "sys/dev/misc/psm/psm.c:2014", "sys/bus/isa/isahint.c:121-129", "sys/dev/acpica/acpi.c:419-421" ], "poc_changes": "not a seeded-code PoC: the trigger is a loader-hint configuration (trigger_hints.txt) driving an in-tree code path; no source had to be corrected. Two restore attempts stumbled on grep -v exit semantics (all file lines were hint lines -> empty output -> exit 1 -> && mv skipped); final restore used truncate.", "attempts": 3, "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": 480, "guest_dirty": 0, "build_cmd": "findings/poc/DF-5641/build.sh (loader-hint install; no compilation)", "run_cmd": "findings/poc/DF-5641/run.sh (hinted reboot -> devinfo/dmesg/vmstat capture -> restore)", "code_hash": "eff266f0a1f8a65bcb5215672add92e6f758f35b2a4e8e770a21702bf41172e8", "notes": "Pass-2 sweep of the rest of the file found nothing actionable: sole rl deref is guarded (isa.c:91-92); machintr_legacy_intr_cpuid(start) at isa.c:100 is KKASSERT-bounded in the IO-APIC ABI (ioapic_abi.c:1122-1125) and arg-ignoring in the ICU ABI (icu_abi.c:399-402), always an in-tree driver constant here; rid bounds complete for the non-default path (isa.c:94-115, isavar.h:63-66) and the default path reads only pre-validated entries created via isa_set_resource (isa_common.c:893-902); isa_setup_intrs trailing NULL is the desc parameter, nexus derives cpuid from rman_get_cpuid (nexus.c:522-536); no user/hint/loader input reaches this files arithmetic, no locks/refcounts held. Reserved IDs DF-5642..DF-5653 unused (clean beyond this Info finding).", "recommended_fix": "Compute the resource-list pointer only for direct ISA children (rl = &DEVTOISA(child)->id_resources when !passthrough, NULL otherwise) in isa_alloc_resource/isa_release_resource, so grandchild ivars are never cast to struct isa_device.", "fix_status": "not_testable", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "fix.diff authored post-verification and git-apply --check-verified against pristine sys/, but not kernel-rebuilt: Info-severity hardening with no runtime misbehavior to diff (the baseline run itself demonstrates the path executes harmlessly); the change only narrows when the ivars cast happens and alters no behavior for any in-tree caller.", "fix_evidence": "findings/poc/DF-5641/fix.diff (git apply --check clean); VERDICT.md Fix section" } |