⬢ DragonFlyBSD Kernel Audit
DF-5641 / verdict.json
← back to finding ↓ download raw
{
  "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"
}