# DF-0716 — smb_strdupin ignores copyin return value — TOCTOU race

## Summary
`smb_strdupin` (`sys/netproto/smb/smb_subr.c:113-131`) calls `copyin(s, p, len)`
at line 129 but **ignores its return value**. A TOCTOU race (racing thread
toggling a page between the length loop and the bulk copyin) causes the bulk
`copyin` to fault partway, leaving the `kmalloc`'d buffer (NOT zeroed) partially
filled with **stale kernel heap data** from a previous `M_SMBSTR` allocation.
The non-NULL buffer is returned to the caller (`smb_usr.c:308`) and used as
`t2p->t_name` — transmitted to the attacker-controlled SMB server via TRANS2.

## Build
```sh
# Build the kernel module test harness + userspace race driver
make                          # strdup_test.ko (kernel module)
cc -o strdup_race strdup_race.c -lpthread
```

## Run
```sh
# Must be root: load smbfs.ko (provides smb_strdupin) + test harness, then race
kldload smbfs
kldload ./strdup_test.ko
./strdup_race [iterations]    # default 100000
```

## Expected (bug present, unpatched)
Most runs: `RACE WON: 0` (the race is extremely narrow — ~1 in 200K+).
Occasionally: `RACE WON: N` with stale bytes (e.g. `b0 3b 02 00 00 00 00 00`)
at the page-boundary straddling positions (bytes 120-127), proving the copyin
return is ignored and stale slab contents are returned.

## Expected (fixed)
`RACE WON: 0` always — the fixed `smb_strdupin` checks the copyin return and
returns NULL on failure (caller handles NULL → ENOMEM). No stale bytes possible.

## Why a test harness module?
`smb_strdupin` is only reachable via `SMBIOC_T2RQ` → `smb_usr_t2request`
(`smb_usr.c:308`), which requires `sdp->sd_share != NULL` (`smb_dev.c:218`),
which requires `SMBIOC_OPENSHARE` → `smb_smb_treeconnect` → a live SMB server.
No SMB server is available on the audit guest. The `strdup_test.ko` module calls
`smb_strdupin` directly (bypassing the SMB protocol) to characterize the
primitive. This is a **test harness**, not an exploit — the finding is root-only
and there is no escalation.

## Fix
`fix.diff` changes `smb_strdupin` (`smb_subr.c:128-130`):
1. Add `M_ZERO` to `kmalloc` — defense-in-depth (buffer zeroed even if copyin fails).
2. Check `copyin` return — if non-zero, `kfree(p)` and `return NULL`.

This matches the pattern already used by `smb_memdupin` (`smb_subr.c:144-147`).
