# DF-5393 — isa_find_memory unbounded candidate loop (boot stall)

## What this proves

`isa_common.c:isa_find_memory()` (lines 128-148) searches a candidate
window for each PnP memory descriptor:

```c
for (start=..., end=..., size=..., align=...;
     start + size - 1 <= end;            /* no wrap guard */
     start += MAX(align, 1)) {           /* align can be 1 */
        bus_set_resource(...); res[i] = bus_alloc_resource(...);
        if (res[i]) break;
}
```

Nothing bounds the number of rman allocation attempts: iteration count =
(end-start)/align, attacker-controlled up to 2^32 (MEMORY32_RANGE supplies
32-bit start/end and a 32-bit align — pnpparse.c:295-300 — with align=1
perfectly legal; MEMORY_RANGE only coerces align==0 to 0x10000, memory32
doesn't even do that). When the window is already claimed (every
bus_alloc_resource fails — arrangeable by resource conflicts, which a
crafted card's other descriptors or system usage provide), the loop grinds
the resource manager at boot with zero progress.

## Reproduced (measured)

The pnphack harness (see ../DF-5392/, same source) creates a child whose
single MEMORY32_RANGE descriptor spans a 4MB window fully covered by a
resource held by a second child. `isa_find_memory()` then iterates all
4,194,304 candidates at align=1:

```
PNPHACK[stall]: ice[0] prio=0 nmem=1 nport=0 nirq=0 ndrq=0
PNPHACK[block]: window [0xe0000000-0xe03fffff] held: YES
...
PNPHACK: config_cb(p61)   ... t=1791069799.927439 (+302946 usec since identify)
PNPHACK: config_cb(stall) ... t=1791069800.684457 (+1059964 usec since identify)
```

**~757ms for a 4MB window ⇒ ~0.18 usec/iteration.** Extrapolation to the
maximum crafted window (start=0, end=0xFFFFFFFF, size=1, align=1):
2^32 * 0.18us ≈ **13 minutes per descriptor**, and up to ISA_NMEM=8
descriptors per config, 9 configs per logical device, unbounded logical
devices per card — hours of boot-time kernel lockup from a handful of PnP
bytes, with the bus probe serialized behind it.

Run: `kldload /usr/obj/usr/src/sys/bus/isa/hack_a/pnphack.ko` (same module
as DF-5392 run-A; the stall children are created unconditionally).

## Fix

`isa_find_memory` gains a wrap guard (`start <= end && start + size - 1 <=
end`) and a per-range attempt cap (`ISA_FIND_MAX_TRIES` = 65536, ~12ms
worst case) — included in ../DF-5392/fix.diff. On the patched kernel the
stall child's callback returns in single-digit milliseconds (see
fix_run_a.log in ../DF-5392/).
