# DF-3675 — VERDICT

**status: inconclusive (no MPT hardware on guest; source-certain arithmetic)**

## Root cause

```c
/* sys/dev/disk/mpt/mpt_cam.c:3131-3133 */
	ccb = req->ccb;
	ccb->csio.resid =
	    ccb->csio.dxfer_len - le32toh(scsi_io_reply->TransferCount);
```

`TransferCount` is a U32 field of the IOC's DMA'd SCSI_IO_REPLY frame with
no clamping: an IOC reporting more bytes transferred than the command's
`dxfer_len` underflows the unsigned subtraction, so CAM and userland see
`resid` near 4 G (`dxfer_len - TransferCount` mod 2^32). The driver only
special-cases `TransferCount == 0` under `MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH`
(`mpt_cam.c:3163-3176`); for DATA_OVERRUN (`:3198`) and every other status
the bogus resid flows out untouched.

Consumers:
- pass(4) copies the full CCB back to the caller — the huge resid is
  directly visible to the pass user (correctness/integrity of upper-layer
  software that trusts resid);
- cd(4)/da(4) use resid for residual handling and error reporting; a resid
  greater than dxfer_len violates CAM's invariant and can mis-drive retry /
  dump accounting (e.g. da dump residual bookkeeping).

Threat: requires an IOC/firmware reporting a wrong TransferCount (or real
overrun reporting) — hardware-trust class. No memory-safety consequence in
the driver itself; impact ceiling is wrong data-accounting visible to
userland and possibly a wedged dump/retry path. Severity Low.

## Fix (also matches the defensive style used for sense data)

```diff
--- a/sys/dev/disk/mpt/mpt_cam.c
+++ b/sys/dev/disk/mpt/mpt_cam.c
@@ -3129,7 +3129,13 @@ mpt_scsi_reply_frame_handler(struct mpt_softc *mpt, request_t *req,
 	sstate = scsi_io_reply->SCSIState;
 
 	ccb = req->ccb;
-	ccb->csio.resid =
-	    ccb->csio.dxfer_len - le32toh(scsi_io_reply->TransferCount);
+	{
+		uint32_t xferred = le32toh(scsi_io_reply->TransferCount);
+		if (xferred > ccb->csio.dxfer_len)
+			ccb->csio.resid = 0;	/* IOC over-reported */
+		else
+			ccb->csio.resid = ccb->csio.dxfer_len - xferred;
+	}
```

## Guest verdict

inconclusive — no MPT hardware; the underflow is proven by inspection
(unsigned U32 arithmetic, no clamp) and matches upstream FreeBSD
(mpt_cam.c `ccb->csio.resid = ccb->csio.dxfer_len -
le32toh(scsi_io_reply->TransferCount);` — shared bug).

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