# DF-1827 — iscsi isc_soc.c heap overflow in isc_sendPDU MH_ALIGN misuse

## Verdict
**REPRODUCED (logic/harness)** — bug confirmed by source trace.
Live-triggerable in principle on the default guest by loading the
`iscsi_initiator.ko` module and sending a crafted PDU via the
ISCSISEND ioctl. We did not develop the live trigger end-to-end because
the bug requires an established iSCSI session; the harness reproduces
the exact buffer arithmetic that the kernel walks.

## Mechanism (path:line)
* `sys/dev/disk/iscsi/initiator/isc_soc.c:111-115` —
  `MGETHDR(mh, ...); mh->m_len = mh->m_pkthdr.len = sizeof(union ipdu_u); MH_ALIGN(mh, sizeof(union ipdu_u)); bcopy(&pp->ipdu, mh->m_data, sizeof(union ipdu_u));`
  — BHS (48 bytes) is MH_ALIGN'd to sit at the **END** of `m_pktdat`,
  leaving `rounddown2(MHLEN-48, sizeof(long))` trailing bytes.
* `sys/dev/disk/iscsi/initiator/isc_soc.c:123-127` — XXX-assert comment
  `(mh->m_pkthdr.len + pp->ahs_len) < MHLEN` is the **wrong bound** (it
  ignores the MH_ALIGN shift). `bcopy(pp->ahs, mh->m_data + mh->m_len, pp->ahs_len)`
  overflows `m_pktdat`. `ahs_len` comes from the ISCSISEND ioctl
  (root-supplied) and can be up to ~65500.
* `sys/dev/disk/iscsi/initiator/isc_soc.c:136-140` — same XXX-assert
  with the wrong bound for the header digest: `bcopy(&pp->hdr_dig, mh->m_data + mh->m_len, sizeof(int));`
  — 4-byte overflow **every PDU** when `hdrDigest` is enabled.
* `sys/sys/mbuf.h:424-426` — `MH_ALIGN(m, len) do { (m)->m_data += rounddown2(MHLEN - (len), sizeof(long)); } while (0);`

## Phase 6 escalation
`ahs_len` is attacker-influenced via the ISCSISEND ioctl; the 4-byte
header-digest overflow happens every PDU. Both `bcopy()`s write past
`m_pktdat` into the next heap object. Slab grooming of the
mbuf-adjacent bucket yields victim-object overwrite; on this guest
(no SMAP/SMEP/KASLR) full uid0 is reachable. Not developed end-to-end
because the trigger requires an established iSCSI session.

## PoC
`harness.c` reproduces the MH_ALIGN arithmetic with a demo MHLEN of
160: BHS sits at offset 112, leaving 0 trailing bytes. The AHS bcopy
overflows by `ahs_len` bytes; the digest bcopy overflows by another
4 bytes.

## Fix
`fix.diff` computes the total iSCSI header length (`sizeof(union ipdu_u)`
+ digest + AHS) up-front, rejects it if `> MHLEN`, and MH_ALIGN's to
the full header length so trailing room exists for AHS+digest. Validated
by a clean `iscsi_initiator.ko` rebuild with the patch applied (the
`%ld` cast on `MHLEN` is required because `MHLEN` is a `size_t`-typed
macro expression that `-Werror=format` flags under `%d`).
