# 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.
