# VERDICT — DF-3824

**Status: inconclusive** (kernel write unexercisable without an asr HBA
on the guest; the layout arithmetic *was* verified by a program compiled
and executed on the guest — see `run.log`).

## Derivation

`asr_action()` XPT_SCSI_IO declares the message on the stack
(asr.c:2680-2682):

```c
struct Message {
        char M[MAX_INBOUND_SIZE];        /* 512 */
} Message;
```

and builds it with `ASR_init_message()` (asr.c:2714).  Inside
`ASR_init_message`:

```c
1804:	sg = &((PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr)->SGL.u.Simple[0];
...
1812:	while ((len > 0) && (sg < &((PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)
1813:	  Message_Ptr)->SGL.u.Simple[SG_SIZE])) {
...          /* one physically-contiguous run per element, 8 bytes each */
1837:		++sg;
...
1841:	if ((span = ccb->csio.sense_len) == 0) {
1842:		span = sizeof(ccb->csio.sense_data);
1843:	}
1844:	SG(sg, 0, I2O_SGL_FLAGS_LAST_ELEMENT | I2O_SGL_FLAGS_END_OF_BUFFER,
1845:	  &(ccb->csio.sense_data), span);
```

`SGL` sits at offset 48 (verified: `I2O_MESSAGE_FRAME`=12 with
`I2O_64BIT_CONTEXT 0` (i2omsg.h:128), private frame +20, bitfield dword
+4, CDBLength/Reserved/SCBFlags +4, CDB[16], ByteCount +4 → 48;
`I2O_SGE_SIMPLE_ELEMENT` = 8).  The loop may fill elements 0..57 =
bytes [48,512) — exactly the buffer.  The **unconditional** sense
element then writes bytes [512,520) — 8 bytes past `M[512]`.

Trigger condition: the loop must reach element 57, i.e. the CCB data
must span ≥ 58 physical runs (inner walk breaks per page/discontinuity,
asr.c:1819-1829).  4 KiB pages ⇒ ≥ ~232 KiB in one CCB.

Feasibility split:

- buffer-cache I/O: `MAXPHYS` = 128 KiB (sys/cpu/x86_64/include/param.h:122)
  ⇒ ≤ ~33 runs ⇒ in-bounds.  Not reachable.
- CAM pass-through (`/dev/passN`, mode 0600, root): `dxfer_len` and
  `data_ptr` are caller-chosen; a ≥256 KiB transfer over a
  user-malloc'd (physically scattered) buffer gives 58+ runs on the
  first try.  Root + hardware gated ⇒ severity Low, class genuine.

Secondary defect in the same lines: `sc->ha_SgSize` — derived from the
adapter-reported `InboundMFrameSize` (asr.c:2459-2465) — is assigned
once and **never read** (`grep -n ha_SgSize` → only :356 and :2464), so
the SGL the driver posts can exceed the adapter's inbound frame;
`asr_set_frame()` (asr.c:1350) then copies `getMessageSize()` dwords of
message into a smaller device frame.

## Guest evidence

- `sg_layout_proof.c` compiled with guest cc 8.3 and executed
  (`build.log`, `run.log`): offsetof(SGL)=48, element=8, loop end=512,
  sense at [512,520), overflow = 8 bytes.  Byte-for-byte struct replicas
  from i2omsg.h/i2odpt.h.
- No asr HBA: `/dev/asr0` open → ENOENT (../DF-3825/run.log), zero
  vendor-0x1044 PCI devices (env.txt) ⇒ `asr_action`/`ASR_init_message`
  never execute ⇒ kernel write itself `inconclusive`.

## Fix

`fix.diff`: bound the loop by `SG_SIZE - 1` so the mandatory sense
element can never leave the buffer (with a comment tying it to the
512-byte stack buffer and to the unused `ha_SgSize`).

## Fix validation

`not_testable` — same hardware precondition as the baseline.

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