# DF-4178 — Verification Verdict

**Status:** inconclusive (hardware-gated: no 3ware Escalade controller in the QEMU guest)
**Impact:** none on this guest (source-certain kernel memory corruption on affected hardware)
**Confidence:** likely (control flow source-certain; trigger needs a controller that completes a command after the 5 s poll window)

## Mechanism (source trace)

1. `twe_ioctl` TWEIO_GET_PARAM → `twe_get_param()` (sys/dev/raid/twe/twe.c:770)
   with `func == NULL` uses `twe_immediate_request()` (twe.c:810).
2. `twe_immediate_request()` (twe.c:981) sets `tr->tr_status = TWE_CMD_BUSY`,
   `twe_map_request()` posts the command — `twe_start()` (twe.c:1126-1158)
   sets BUSY and `twe_enqueue_busy(tr)` (twe_freebsd.c:1144 via
   twe_setup_data_dmamap → twe_start).
3. Poll loop (twe.c:1003-1006) waits at most 5000 ms, then falls out and
   **returns 1 with the request still on `twe_busy` and still posted to the
   controller** (twe.c:1010).
4. Caller error path `twe_get_param err:` (twe.c:826-833) —
   `twe_release_request(tr)` → `twe_enqueue_free(tr)` (twe.c:1623-1631).
   The request is now double-linked (busy + free).
5. The free list turns over in microseconds under I/O; another consumer
   pops the request (`twe_get_request`, twe.c:1594) and re-submits it.
6. The controller eventually completes the *old* command:
   `twe_done()` (twe.c:1177) → `tr = sc->twe_lookup[rq.u.response_id]`
   (twe.c:1199).  `tr->tr_status != TWE_CMD_BUSY` → only prints
   "completion event for nonbusy command" (twe.c:1203-1204) **and then
   falls through**:
   - `tr->tr_status = TWE_CMD_COMPLETE` (twe.c:1205) — clobbers the new
     owner's SETUP/BUSY state;
   - `twe_remove_busy(tr)` (twe.c:1209) — `TAILQ_REMOVE` on a request that
     is *not* on `twe_busy`: writes through the stale `tr_link` pointers
     (twevar.h:249-253) — kernel memory corruption;
   - `twe_enqueue_complete(tr)` → `twe_complete()` dispatches the *new*
     owner's `tr_complete` (e.g. `twe_completeio`, twe.c:1017 →
     `twed_intr(bio)` → `biodone()` on a bio still in flight).

Identical release-while-busy patterns: `twe_set_param` out: (twe.c:909-914),
`twe_dump_blocks` (twe.c:506-510), `twe_init_connection` (twe.c:946-947).

Related but distinct: `twe_wait_request()` (twe.c:960-973, TWEIO_COMMAND)
has *no* timeout at all — a never-completing controller hangs the ioctl
forever, each such ioctl permanently consuming one of the 255 requests.

## Why it cannot be reproduced on this guest

The twe driver binds to PCI vendor 0x13c1 devices only
(twe_freebsd.c:172-174).  The QEMU guest has no 3ware controller
(`pciconf -l` shows no 13c1 device, no /dev/twe* node exists), so the
trigger path cannot be exercised.  PoC builds and runs; `open("/dev/twe0")`
fails with ENOENT (see run.log).

## Phase V: escalation assessment

The primitive (once a late completion arrives) is a write-what-where-ish
TAILQ corruption inside the driver's request queues plus a forced
completion callback with attacker-influenced `tr_private`/`tr_data` —
enough for kernel RCE in principle on affected hardware.  On this guest the
path is not exercisable at all (device absent), so no chain can be
developed here.  Gate: root-only control device (0600 root:operator,
twe_freebsd.c:339-342) + a controller that completes commands late.

## Fix validation

`fix.diff` (two hunks: timeout path unmaps + dequeues + marks ERROR;
`twe_done` consumes-and-drops stale responses instead of falling through)
applies cleanly to the guest's /usr/src and was batch-compiled with the
other four fixes of this batch into X86_64_GENERIC — see fix_build.log /
fix_verdict in verdict.json.

Residual (documented in fix.diff header): the caller still kfree()s the
512-byte parameter buffer after a timeout while the controller may
late-write it; a full fix needs a controller-side abort (TWE_OP_ABORT)
before freeing.

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