{
  "finding_id": "DF-5443",
  "status": "reproduced",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "REPRODUCED on DragonFly 6.5-DEVELOPMENT (X86_64_GENERIC, QEMU). A KLD compiling the REAL unmodified sys/bus/isa/pnp.c (verbatim #include; only inb/outb/kmalloc/kfree and three global names macro-substituted, DRIVER_MODULE neutered) was driven by a virtual PnP card implementing the serial-isolation protocol (checksum-valid 72-bit ID served LSB-first, PNP_STATUS/PNP_RESOURCE_DATA service). A card that streams a large-tag header (0x84, len 2048) and then stalls mid-descriptor \u2014 i.e. takes the ordinary PnP device failed to report resource data path (pnp.c:218-221) after >1024 delivered bytes \u2014 forces pnp_read_bytes() through its growth path (kmalloc 3072, kfree of the 1024 buffer at pnp.c:512) and then into the short-read EINVAL return that does NOT update *resourcesp (pnp.c:517-518). pnp_read_resources() propagates the stale freed pointer at out: (pnp.c:576-580) and pnp_isolation_protocol() frees it again at cleanup (pnp.c:673-674): observed kfree(A) [growth]; kfree(A) [cleanup] then panic: memory chunk 0xfffff8008db3b400 is already free! with stack _kfree <- engine identify <- isa_driver_added <- devclass_add_driver \u2014 the genuine kldload path. Primitive = kernel-heap double free (CWE-415) of a 1024-byte M_TEMP block with attacker-chosen timing, plus a leak of the grown buffer; terminal outcome on this kernel is a deterministic panic (allocator chunk_mark_free check). uid0 not pursued: no unprivileged-user input path \u2014 trigger is PnP card data at boot/driver-load (crafted/counterfeit hardware or VM device), same attacker model as DF-5392/5393/5394; for that attacker the primitive is boot-time ring-0 heap corruption. FIX VALIDATED on rebuilt kernel #1 (fix.diff): identical fault injection now frees the LIVE grown buffer exactly once at cleanup (kfree(3072-buffer)), no DOUBLE FREE, no panic, kldload RC=0, witness clean \u2014 leak also fixed.",
  "exploit_chain": "crafted/misbehaving ISA-PnP card (or emulated PnP device in a VM) -> pnp_identify read-port loop -> pnp_isolation_protocol -> pnp_get_serial (valid checksum) -> pnp_read_resources -> pnp_read_bytes growth (kmalloc B, kfree A at pnp.c:512) -> card stalls -> pnp_get_resource_info returns short -> EINVAL without out-param update (pnp.c:517-518) -> pnp_read_resources out: propagates stale A (pnp.c:577-579) -> pnp_isolation_protocol cleanup kfree(A) again (pnp.c:674) -> heap double free -> panic on this kernel (chunk_mark_free) / free-list poisoning (two live owners of one 1024-byte block) on kernels without the check -> boot-time ring-0 memory corruption under attacker control.",
  "evidence": "run.log + serial_runA_full.log (baseline: kmalloc(1024)=0xfffff8008db3b400, kmalloc(3072)=0xfffff8008dc05500, kfree(A) at growth, short-read message, kfree(A) again, panic); panic.txt (panic: memory chunk ... is already free!, full trace); fix_run.log (patched kernel: same stream, kfree of 0xfffff8008dc05500 at cleanup, RUN_A_RC=0, witness clean); fix.diff (out-param propagation hunk); fix_build.log (full 4299-step kernel build of the fixed tree); rig/ (pnprig.c harness + hack_dfa wrapper + build.sh + run_A.sh)",
  "kernel_refs": [
    "sys/bus/isa/pnp.c:493-526",
    "sys/bus/isa/pnp.c:506-515",
    "sys/bus/isa/pnp.c:517-518",
    "sys/bus/isa/pnp.c:536-581",
    "sys/bus/isa/pnp.c:576-580",
    "sys/bus/isa/pnp.c:593-677",
    "sys/bus/isa/pnp.c:673-674",
    "sys/bus/isa/isa_common.c:816-831"
  ],
  "poc_changes": "Self-authored rig (no seed). (1) The virtual card must serve serial bits LSB-first per byte \u2014 the kernel assembles data[i/8] by shifting right and ORing into 0x80 (pnp.c:192), so MSB-first serving yields bit-reversed IDs and checksum failure; fixed after attempt 1 (simulated the LFSR offline). (2) The kfree-witness initially counted per-address frees and false-positived on legal allocator address recycling during buffer growth; replaced with liveness tracking (alloc marks live, free of non-live chunk = double free). (3) pnp_identify() refuses to run on a DS_ATTACHED bus (pnp.c:698-701 rescan guard), so the rig drives the identical read-port loop (pnp.c:713-720) calling pnp_isolation_protocol() directly \u2014 the engine itself is untouched.",
  "attempts": 3,
  "guest_uname": "baseline: DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 / fixed: #1: Mon Oct 5 16:47:13 UTC 2026 (fix-validated kernel)",
  "runtime_sec": 6900,
  "guest_dirty": 0,
  "build_cmd": "(cd /usr/src/sys/bus/isa/hack_dfa && make obj && make depend && make)   # rig KLD; fix kernel: cd /usr/src && make -j3 nativekernel KERNCONF=X86_64_GENERIC && make installkernel KERNCONF=X86_64_GENERIC",
  "run_cmd": "kldload /usr/obj/usr/src/sys/bus/isa/hack_dfa/rigdfa.ko   # baseline: panic; fixed: RC=0",
  "code_hash": "e4db996c97f7a4791e143a54d555297b7493f7759a96af75f02e72d484daba75",
  "notes": "Terminal impact recorded as panic (deterministic on this kernel via the allocators double-free check); the underlying primitive is a heap double free of a 1024-byte M_TEMP block with attacker-controlled growth boundary and timing, plus a guaranteed leak of the replacement buffer (up to 64 KiB+ per attempt, repeatable per read-port scan). Reachability is NOT limited to malicious cards: any flaky PnP card that stalls mid-resource-transfer after >1 KiB takes this path at every boot. Severity Medium (hardware-trigger model, consistent with DF-5393/DF-5394); memory-corruption bucket. The same error-path shape exists for the first-call failure (leak-only face: *resourcesp stays NULL, the initial 1024-byte allocation leaks per port per boot).",
  "recommended_fix": "In pnp_read_bytes(), publish *resourcesp/*spacep (and *lenp semantics) BEFORE the pnp_get_resource_info() attempt so the caller always tracks the live buffer \u2014 full unified diff in fix.diff (also fixes DF-5444/DF-5445).",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "Single-fix kernel (nativekernel X86_64_GENERIC + fix.diff, #1 Mon Oct 5 16:47:13): the exact baseline-panic fault injection now completes with kfree of the LIVE grown buffer (0xfffff8008dc05500) exactly once at cleanup, no DOUBLE FREE detected, no panic, kldload RC=0, witness clean, guest healthy. Baseline bad behavior GONE; leak of the grown buffer also eliminated.",
  "fix_evidence": "fix_run.log (patched-kernel dmesg sequence + RUN_A_RC=0), fix_build.log (full kernel build), fix.diff (git apply --check clean against the read-only sys/ tree)",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Mon Oct 5 16:47:13 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64"
}