# DF-4738 VERDICT — collision-blind, unbounded static bus-number allocator in cbb_pci_attach()

**Status: not_reproduced at runtime (hardware-gated — no CardBus bridge on
the audit guest); allocator logic defect certain, demonstrated by a
guest-run verbatim replica of the renumbering block; real-world
manifestation requires a specific (but historically real) firmware state.**

## Root cause (path:line)

`sys/dev/pccard/pccbb/pccbb_pci.c:299`:

```c
static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */
```

and the renumbering block `pccbb_pci.c:344-359`:

```c
pribus = pci_read_config(brdev, PCIR_PRIBUS_2, 1);
if (sc->secbus == 0 || sc->pribus != pribus) {
        if (curr_bus_number <= sc->pribus)
                curr_bus_number = sc->pribus + 1;
        ...
        sc->secbus = curr_bus_number++;
        sc->subbus = curr_bus_number++;
        pci_write_config(brdev, PCIR_SECBUS_2, sc->secbus, 1);
        pci_write_config(brdev, PCIR_SUBBUS_2, sc->subbus, 1);
}
```

Defect axes:

1. **Collision-blind.** When firmware leaves a CardBus socket unprogrammed
   (`SECBUS == 0`) — the state this block exists to handle — the socket is
   given `curr_bus_number`, which starts at 2 and is adjusted only for
   *this bridge's* primary bus (`:346-347`). Bus numbers that firmware
   already assigned to other bridges elsewhere in the tree (AGP/PCIe root
   ports routinely own bus 2..N) are never consulted. Two bridges then own
   the same bus number: type-1 config cycles intended for the CardBus
   card's bus are also claimed by the other bridge, so config reads/writes
   for a CardBus card can hit an unrelated real device — a card driver can
   program its BARs into, say, the display controller, or read the VGA
   controller's ID as the card's. Config-space corruption of unrelated
   devices (writable command register/BARs -> device DMA anywhere) is the
   worst-case fallout. (FreeBSD later rewrote this allocator; DragonFly
   still carries the 2005 code, as its own comment admits: "XXX EVILE BAD".)
2. **Unbounded 8-bit space.** `curr_bus_number` is an `int` with no <=255
   check; `sc->secbus`/`sc->subbus` are `u_int8_t` (pccbbvar.h:68-69) and
   `pci_write_config(..., 1)` truncates to a byte. Socket #127 draws
   `secbus_reg = 256` -> softc `secbus = 0` — the very "unconfigured"
   sentinel `:345` treats as invalid: re-renumbering on any re-probe/resume
   while cardbus children still reference bus 0 (= host bus). Subsequent
   sockets silently alias earlier bus numbers (mod 256).
3. Each socket unconditionally consumes two bus numbers (`:353-354`) even
   when one would do, accelerating exhaustion; and `subbus` is written
   before the guard-free increments, so a partial failure leaves config
   registers inconsistent.

Reachability: attach-time only, driven by PCI config state (firmware).
No unprivileged-user trigger — this is a firmware/hardware-state defect on
machines that actually have CardBus bridges (laptops of the yenta era).

## Proof

`cbb_busnum_alloc_demo.c` replicates `:299` and `:344-359` verbatim
(DEVPRINTF dropped) with fixture bridges; compiled with guest cc 8.3 and
executed on the guest (run.log):

* Case 1 (firmware gave a PCIe root port bus 2; cbb socket SECBUS=0):
  cbb0 is renumbered to secbus=2 -> `=> COLLISION: two bridges now own
  bus 2`.
* Case 2 (128 sockets): socket #127 -> `secbus_reg=256 -> u_int8_t
  secbus=0`; no >255 check exists.

Hardware gate: the audit guest's entire PCI inventory is
i440FX/PIIX3/PIIX4-PM/virtio — no class 0x0607 (CardBus) device
(guest_hw_evidence.txt). cbb(4) is compiled into the kernel but never
attaches, so the in-kernel path cannot execute; hence not_reproduced with
certain allocator logic.

## Fix

Minimal guard (fix.diff): fail attach (`goto err`) when
`curr_bus_number > 254` instead of truncating into the u_int8_t fields.
The collision axis needs the real fix: allocate secondary bus numbers
centrally (walk the already-enumerated tree for the highest assigned bus,
or delegate to the PCI core's bus-number allocation, as FreeBSD's later
pccbb rework does) rather than a driver-static counter seeded at 2.

## Fix validation

Not testable on this guest (no CardBus bridge; a single-fix kernel build
has no CardBus attach to observe). The guard's arithmetic (254+1 = 255
max) and the truncation semantics are exercised by the demo's case 2.

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