# DF-0734 — Negative `ioc_setupcnt` bypasses signed upper-bound check → >131KB kernel stack OOB read

## Verdict: REPRODUCED (panic) + FIX VALIDATED

## Bug mechanism

**File:** `sys/netproto/smb/smb_usr.c:299`
**Bug:** `if (dp->ioc_setupcnt > 3) return EINVAL;` — `ioc_setupcnt` is `int`, so a negative value (e.g., `-1`) passes this SIGNED upper-bound check (`-1 > 3` is false).

**Exploitation chain:**
1. `smb_usr.c:304` — `len = t2p->t2_setupcount = dp->ioc_setupcnt;` — `t2_setupcount` is `u_int16_t`; `-1` (int) becomes `65535` (u_int16_t).
2. `smb_usr.c:305` — `if (len > 1)` — `len` is `int = -1`; `-1 > 1` is false; `t2_setupdata` stays pointing at the internal `t2_setup[2]` array (4-byte stack buffer in `struct smb_t2rq`).
3. `smb_rq.c:629-630` — `for (i = 0; i < t2p->t2_setupcount; i++) mb_put_uint16le(mbp, t2p->t2_setupdata[i]);` — `t2_setupcount = 65535` (u_int16_t), `i` is `int`; loop reads 65535 × 2 = 131,070 bytes from a 4-byte stack array.
4. **Result:** ~131KB OOB read past the kernel stack. On this kernel, the read crosses the stack guard page → **`panic: vm_fault: fault on stack guard`** in `smb_t2_request()` called from `smb_usr_t2request()`.

## Trigger setup

- **rogue_smb.c** — Minimal SMB1/NetBIOS-over-TCP server (C). Handles NB session request → SMB NEGOTIATE (CORE dialect) → SESSION_SETUP_ANDX → TREE_CONNECT_ANDX. Listens on 127.0.0.1:139.
- **trigger.c** — Uses the `libsmb` API (same library as `mount_smbfs`) to establish a VC+share against the rogue server via `SMBIOC_LOOKUP`, then issues `SMBIOC_T2RQ` with `ioc_setupcnt = -1`.

## Build & Run

```sh
# Build the rogue server
cc -o rogue_smb rogue_smb.c

# Build the trigger (requires libsmb)
cc -o trigger trigger.c -lsmb -I/usr/src/contrib/smbfs/include

# Run (must be root; load smbfs module first)
kldload smbfs
./rogue_smb 139 &    # start rogue SMB server
./trigger            # trigger the bug
```

## Expected behavior

- **Unpatched kernel (#0):** `panic: vm_fault: fault on stack guard` — the OOB read crosses the kernel stack guard page during TRANS2 request construction. Guest goes down.
- **Patched kernel/module:** `SMBIOC_T2RQ` returns `EINVAL` (errno=22). No panic. Guest stays up.

## Panic signature (baseline)

```
panic: vm_fault: fault on stack guard, addr: 0xfffff801187bc000
smb_t2_request() at smb_t2_request+0x2b7
smb_usr_t2request() at smb_usr_t2request+0xc6
```

## Fix

`smb_usr.c:299`: Add `dp->ioc_setupcnt < 0 ||` to the bounds check:

```diff
-	if (dp->ioc_setupcnt > 3)
+	if (dp->ioc_setupcnt < 0 || dp->ioc_setupcnt > 3)
 		return EINVAL;
```

Since `smb_usr.c` is compiled into the `smbfs.ko` loadable module (not the base kernel), the fix can be validated by rebuilding just the module and hot-swapping it.
