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

exca_activate_resource leaks the ExCA window when parent BUS_ACTIVATE_RESOURCE fails (and exca_mem_map on its memreg error return) β€” permanent per-socket window-exhaustion DoS

Summary

The window bit is claimed via io_map/mem_map before the parent activation; if the parent fails, the error returns without releasing it, and deactivate never unwinds it (gated on RF_ACTIVE which a failed activation never sets). Each failed activation permanently burns one of 5 memory windows or one of only 2 I/O windows - afterwards every 16-bit PC Card on that socket fails to map resources until reboot. Hardware-gated per-socket availability attack (insert/remove churn with failing parent activations). Same defect on mem_map's early return. Release-on-error fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4572 Β· 8 files
FileTypeDescriptionSize
VERDICT.md β€” 4.4 KB ↓ raw
README.md β€” 902 B ↓ raw
run.sh β€” 172 B view raw
run.log β€” 941 B view raw
env.txt β€” 682 B view raw
fix.diff β€” 1.3 KB view raw
manifest.json β€” 1.2 KB view raw
verdict.json β€” 2.8 KB view raw

DF-4572 evidence pack β€” exca window leak on activation failure

Status: INCONCLUSIVE (PoC not runnable: guest has no CardBus/PCMCIA hardware). The finding itself is a certain code-level defect; see VERDICT.md for the full path:line trace and the on-hardware trigger procedure.

Contents: VERDICT.md full narrative + reachability trace + trigger procedure run.sh guest-side hardware-presence check (what was executed) run.log output of run.sh on the audit guest (NO_CARDBUS_BRIDGE, ...) env.txt guest uname + device state fix.diff inspection-validated fix (releases the leaked window bits) manifest.json artifact catalog verdict.json machine verdict (status: inconclusive; persist_poc-compatible)

Reproduce the environment check: ./run.sh (on the audit guest or any DF box) Reproduce the finding: requires pccbb hardware β€” see VERDICT.md Β§Trigger.

VERDICT.md
↓ download raw

DF-4572 β€” exca window allocation leaked on activation failure (per-socket DoS)

  • File: sys/dev/pccard/exca/exca.c (pass 2, GLM 5.3)
  • Class: resource leak on error path β†’ availability DoS of a PC Card socket
  • Severity: Low (hardware-gated: requires a pccbb CardBus bridge + 16-bit PC Card)
  • Confidence: certain (code defect), likely (realistic trigger)

Summary

exca_activate_resource() (sys/dev/pccard/exca/exca.c:779) programs an ExCA memory or I/O window (exca_mem_map / exca_io_map, which claim a window via sc->memalloc/sc->ioalloc bits at exca.c:250-255 / 468-473) and only then calls the parent bridge's BUS_ACTIVATE_RESOURCE (exca.c:800). If the parent activation fails, the error is returned without releasing the window bit. exca_deactivate_resource() (exca.c:804-822) only unmaps windows when the resource carries RF_ACTIVE β€” a resource whose activation failed never has it β€” so there is no unwind path at all. Each failed activation permanently consumes one of the socket's 5 memory windows (EXCA_MEM_WINS, excavar.h:72) or one of its 2 I/O windows (EXCA_IO_WINS, excareg.h:229). After enough failures, exca_io_map/exca_mem_map always return 1 and every subsequent 16-bit PC Card on that socket fails to attach.

Sibling instance of the same defect: exca_mem_map() grabs the window bit at exca.c:252 and returns 1 at exca.c:260-262 ("Does not support mapping above 24M") without releasing it. On current DragonFly that branch is unreachable (the only live caller path is pccbb PCI, which sets EXCA_HAS_MEMREG_WIN unconditionally at sys/dev/pccard/pccbb/pccbb_pci.c:332), but it is the same shared code and trivially fixed together.

Reachability (pass-2 trace)

  • Only live consumers of exca.c on DragonFly are the pccbb PCI bridges: exca_reset (pccbb.c:1232), exca_activate_resource/ exca_deactivate_resource (pccbb.c:1286/1294), exca_mem_set_flags (pccbb.c:1390), exca_mem_set_offset (pccbb.c:1406), exca_insert/ exca_removal. The ISA path (exca_probe_slots, pccbb_isa.c:161) is dead: cbb_isa_activate() returns ENOMEM unconditionally (pccbb_isa.c:134-138) so cbb_isa_probe() bails before ever probing slots.
  • exca_activate_resource runs whenever a 16-bit PC Card function driver activates an I/O or memory resource on the socket β€” i.e. at card insertion / driver attach, driven by the cbb event thread and devd.
  • The parent call is BUS_ACTIVATE_RESOURCE(parent=cbb) β†’ rman/PCI mapping of the resource; failure modes include rman range exhaustion and failed pmap/bus-space activation under memory pressure.

Why "inconclusive" (not reproduced here)

The audit QEMU guest has no CardBus/PCMCIA hardware and none can be attached with the standard QEMU machine model (no i82365/pci-to-cardbus bridge emulation):

  • pciconf -l shows no class=0607 device (NO_CARDBUS_BRIDGE)
  • devinfo shows no pccard/cbb/exca devices
  • VGA is QEMU virtio-gpu (0x1234:1111), no drm/i915 modules loaded

The trigger therefore cannot execute on this guest even as root. The defect itself is unambiguous from the source: there is no code path that clears the window bit between exca_io_map/exca_mem_map success and the failing parent BUS_ACTIVATE_RESOURCE, and exca_deactivate_resource is gated on RF_ACTIVE.

Trigger on real hardware (documented procedure)

  1. Machine with a pccbb-class PCI CardBus bridge (e.g. Ricoh RL5c476, TI PCI1420) β€” pciconf -lv | grep -B3 cardbus.
  2. Force repeated failed parent activation for a 16-bit PC Card's resources (e.g. exhaust the rman window the bridge maps into so BUS_ACTIVATE_RESOURCE at exca.c:800 returns non-zero), then remove and re-insert the card (devd hotplug cycles).
  3. After 2 failed I/O activations (or 5 failed memory activations) the socket is dead for 16-bit cards: every subsequent attach logs "exca_io_map: no windows available"-equivalent failure (exca_io_map returns 1 at exca.c:474-475) until reboot.

Fix

Release the window when the parent activation fails, and on exca_mem_map's error return β€” see fix.diff (validated by inspection; cannot build-test a pccbb kernel path on this guest).

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.

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

Fix validated by inspection only: fix.diff restores the window bit on both error paths (exca.c:258-262 and the parent-activate failure in exca_activate_resource) and cannot regress the success path; no pccbb hardware on the guest to build/run a single-fix kernel against.

fix.diff in findings/poc/DF-4572/
↓ fix.diffper-fix-DF-4572

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md (path:line trace + on-hardware trigger); run.log/env.txt (guest hardware absence: NO_CARDBUS_BRIDGE); fix.diff (releases window bits on both error paths)

PoC changes

n/a β€” no PoC build possible; only the environment check run.sh was executed on the guest

Verified recommended fix

Release the ExCA window bit when parent BUS_ACTIVATE_RESOURCE fails, and on exca_mem_map's memreg error return (fix.diff)

Verdict

Code-level defect is certain: exca_activate_resource (exca.c:779-802) claims an ExCA window via exca_io_map/exca_mem_map and then calls the parent bridge's BUS_ACTIVATE_RESOURCE (exca.c:800) with no unwind on failure; exca_deactivate_resource (exca.c:808) is gated on RF_ACTIVE, which a failed activation never sets, so the window bit (5 MEM / 2 IO per socket) is leaked permanently and repeated failures exhaust the socket's windows (exca_io_map returns 1 at exca.c:474). Not runnable on the audit guest: QEMU exposes no CardBus/PCMCIA bridge (no PCI class 0607 device, devinfo has no pccard/cbb/exca, run.log), so impact could not be demonstrated at runtime. Impact ceiling: per-socket availability DoS of 16-bit PC Card resource mapping, hardware-gated (pccbb bridge + card insertion cycles), no kernel memory corruption.