β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-5444

pnp_set_config() panics on card-supplied misaligned memory base (MEMORY32_RANGE/FIXED descriptors have no 256-byte granularity clamp)

Summary

A MEMORY32_RANGE base=0xE0001001 align=1 flows unmodified through pnpparse (which clamps only the 16-bit MEMORY_RANGE variant) -> isa_find_memory honors align=1 -> pnp_set_config panic('bogus memory assignment'). pnprig-verified through the real isa_driver_added->isa_assign_resources flow; granularity-clamp + panic-to-kprintf fix validated (graceful 'can't assign resources').

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5444 Β· 8 files
FileTypeDescriptionSize
README.md β€” 2.2 KB ↓ raw
VERDICT.md β€” 2.5 KB ↓ raw
verdict.json β€” 5.1 KB view raw
manifest.json β€” 984 B view raw
panic.txt β€” 521 B view raw
serial_runB_full.log β€” 2.6 KB view raw
fix_run.log β€” 548 B view raw
env.txt β€” 382 B view raw

DF-5444 β€” pnp_set_config() panics on card-supplied misaligned memory base (sys/bus/isa/pnp.c:260-261)

What

pnp_set_config() (the ISA_SET_CONFIG_CALLBACK installed by pnp_create_devices, pnp.c:456-457) executes panic("pnp_set_config: bogus memory assignment") when the assigned memory base has bits below 0x100 set. The base is card-controlled end-to-end:

  • pnp_parse_desc() PNP_TAG_MEMORY32_RANGE stores a fully arbitrary 32-bit ir_start and ir_align from the card (pnpparse.c:295-300) β€” no 256-byte granularity clamp (unlike PNP_TAG_MEMORY_RANGE at pnpparse.c:266-269 which forces align β‰₯ 0x10000);
  • isa_find_memory() (isa_common.c:128-148) starts its candidate loop at the card-supplied ir_start and steps by MAX(align,1) β€” with align=1 the first candidate is the misaligned base itself;
  • the config callback then panics (pnp.c:260-261).

Same reachability for PNP_TAG_MEMORY32_FIXED (pnpparse.c:323-328, align=1, fixed base).

Trigger model

Crafted ISA-PnP card (or emulated/counterfeit PnP device in a VM) declaring a logical device with MEMORY32_RANGE base=0xE0001001 align=1 size=1. Boot-time / driver-load-time kernel panic = DoS (DS_ATTACHED-gated identify notwithstanding: the kldload→isa_driver_added path runs the whole engine, see DF-5392).

Rig

Same rig/ as DF-5443 (verbatim pnp.c engine + virtual card). Module hack_dfb (script 2): card declares one logical device with the misaligned MEMORY32_RANGE above and a valid END tag. pnp_create_devices (real code) creates the child with the real pnp_set_config callback; isa_driver_added's child loop (isa_common.c:835-862) then runs isa_assign_resources β†’ callback β†’ panic.

Build / Run

(cd /usr/src/sys/bus/isa/hack_dfb && make obj && make depend && make)
kldload /usr/obj/usr/src/sys/bus/isa/hack_dfb/rigdfb.ko

Expected

Baseline: panic: pnp_set_config: bogus memory assignment, trace pnp_set_config <- isa_assign_resources <- isa_driver_added <- devclass_add_driver.

Fixed kernel (fix.diff: pnpparse.c clamps MEMORY32_* granularity to 0x100 and rounds bases to 256; pnp.c degrades gracefully instead of panicking): no panic, warning printed, kldload returns 0.

VERDICT.md
↓ download raw

DF-5444 VERDICT β€” REPRODUCED (kernel panic; card-driven DoS)

Bottom line

panic("pnp_set_config: bogus memory assignment") (sys/bus/isa/pnp.c:261) was triggered through the real kernel flow on the guest by a card declaring MEMORY32_RANGE base=0xE0001001 align=1 size=1. The single-fix kernel (fix.diff) turns the identical stream into a graceful resource rejection.

Chain (all real code; rig only virtualizes the card's port behaviour)

  1. Card bytes β†’ pnp_parse_desc() PNP_TAG_MEMORY32_RANGE stores arbitrary 32-bit ir_start/ir_align β€” no 256-byte granularity clamp (pnpparse.c:295-300), unlike PNP_TAG_MEMORY_RANGE which forces align β‰₯ 0x10000 (pnpparse.c:266-269).
  2. isa_driver_added() child loop (isa_common.c:835-862) β†’ isa_assign_resources() β†’ isa_find_memory() (isa_common.c:128-148): candidate loop starts at the card base and steps by MAX(align,1) β€” with align=1 the first candidate is the misaligned base; rman grants it (0xE0001001 is free on this guest).
  3. Config callback = the real pnp_set_config (installed at pnp.c:456-457) β†’ start & 0xff β†’ panic (pnp.c:260-261).

Same reachability via PNP_TAG_MEMORY32_FIXED (pnpparse.c:323-328: fixed arbitrary base, align=1).

Evidence

Baseline (kernel #0): panic.txt / serial_runB_full.log β€”

panic: pnp_set_config: bogus memory assignment
pnp_set_config() at pnp_set_config+0x192
isa_assign_resources() at isa_assign_resources+0x9e7
isa_driver_added() at isa_driver_added+0x106
devclass_add_driver() ... module_register_init()

Fixed (kernel #1, fix.diff): fix_run.log β€” RUN_B_RC=0, (null) can't assign resources (memory) (rounded base no longer fits the 1-byte window β†’ config rejected β†’ device disabled), guest healthy.

Fix

pnpparse.c: MEMORY32_RANGE/MEMORY32_FIXED granularity clamped to 0x100 with bases rounded up; pnp.c: panic downgraded to kprintf + truncation (defense in depth). Validated above; full diff in fix.diff (shared with the DF-5443/DF-5445 packs; build log in DF-5443/fix_build.log).

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

(No fix.diff for this item: documented recommendation only - see Fix above.)

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

Single-fix kernel (fix.diff, #1 Mon Oct 5 16:47:13): the exact baseline-panic card stream loads with RUN_B_RC=0; the rounded base no longer fits the card's 1-byte window so the config is gracefully rejected ('(null) can't assign resources (memory)'), the device is disabled, no panic, guest healthy. Baseline bad behavior GONE.

fix_run.log (RUN_B_RC=0, resource-rejection message, healthy uptime); fix_build.log (in DF-5443 pack; full kernel build of the fixed tree); fix.diff (git apply --check clean)
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

Confirmed kernel references

Detail

Exploit chain

crafted ISA-PnP card (or VM-emulated PnP device) -> MEMORY32_RANGE base 0xE0001001 align=1 -> pnp_parse_desc stores arbitrary 32-bit start/align (pnpparse.c:295-300) -> ISA_ADD_CONFIG -> isa_driver_added -> isa_assign_resources -> isa_find_memory first candidate = misaligned base, allocated (isa_common.c:130-147) -> id_config_cb = pnp_set_config -> panic('bogus memory assignment') (pnp.c:260-261) -> kernel panic at boot/driver-load = denial of service.

Evidence (decisive lines)

panic.txt + serial_runB_full.log (baseline: panic trace through isa_assign_resources/isa_driver_added); fix_run.log (patched kernel: RUN_B_RC=0, '(null) can't assign resources (memory)', uptime healthy); fix.diff (pnpparse.c granularity clamps + pnp.c panic->kprintf); rig/ (hack_dfb wrapper, script 2)

PoC changes

Same rig as DF-5443 (see its poc_changes). Script 2 serves a 27-byte resource stream: LOGICAL_DEVICE tag (len 5) + MEMORY32_RANGE (0x85, len 17, base/endbase 0xE0001001, align 1, size 1) + END. No kprintf in the card path beyond PNPRIG markers; the panic comes from the unmodified pnp.c text.

Verified recommended fix

Enforce 256-byte memory granularity in pnpparse.c MEMORY32_RANGE/MEMORY32_FIXED (align>=0x100, base rounded up), and replace pnp_set_config()'s panic with a kprintf + base truncation β€” full unified diff in fix.diff.

Verdict

REPRODUCED on DragonFly 6.5-DEVELOPMENT (baseline #0). Same rig family as DF-5443 (verbatim pnp.c engine + virtual card). The card declares one logical device whose MEMORY32_RANGE descriptor carries base=0xE0001001, align=1, size=1. The REAL kernel code path runs end-to-end: pnp_create_devices() creates the child with the real pnp_set_config callback (pnp.c:446-457); after identify returns, isa_driver_added()'s child loop (isa_common.c:835-862) calls isa_assign_resources() -> isa_find_memory() (isa_common.c:128-148) which starts its candidate loop AT the card-supplied base with MAX(align,1)=1 stepping, so the first candidate is the misaligned base itself and rman grants it; the config callback then hits 'if (start & 0xff) panic("pnp_set_config: bogus memory assignment")' at pnp.c:260-261. Observed: 'panic: pnp_set_config: bogus memory assignment' with trace pnp_set_config <- isa_assign_resources <- isa_driver_added <- devclass_add_driver <- module_register_init (the genuine kldload flow). Root cause is the missing 256-byte granularity clamp for MEMORY32_RANGE/MEMORY32_FIXED in pnpparse.c (295-300, 323-328) β€” unlike PNP_TAG_MEMORY_RANGE which forces align>=0x10000 (pnpparse.c:266-269) β€” combined with a panic() as the failure mode in pnp.c. FIX VALIDATED on rebuilt kernel #1 (fix.diff: pnpparse clamps MEMORY32_* alignment to 0x100 and rounds bases to 256; pnp.c downgrades the panic to kprintf + truncation): the identical card stream now loads with RUN_B_RC=0, graceful '(null) can't assign resources (memory)' (rounded base no longer fits the 1-byte window -> config rejected -> device disabled), guest healthy.