# DF-3520 — negative-length `bcopy` amplifier in ng_pptpgre ack processing

**Verdict: NOT REPRODUCED in-kernel on this guest (needs the DF-0596 SMP
TOCTOU first, which is blocked by the CPU-0 netisr serialization); the
arithmetic sink is PROVEN and materially worse than DF-0596's recorded
8-byte OOB write.**

`status = not_reproduced`, `reproduced = 0`, `impact = none (on this
vector)`, `confidence = certain (arithmetic + code)`.

## The sink

`sys/netgraph/pptpgre/ng_pptpgre.c`, ack handler:

```c
:641  const int index = ack - priv->recvAck - 1;
      /* checks: PPTP_SEQ_DIFF(ack, xmitSeq) > 0  -> badAck  (:646)
                 PPTP_SEQ_DIFF(ack, recvAck) <= 0 -> badAck  (:650) */
:668  bcopy(a->timeSent + index + 1, a->timeSent,
          sizeof(*a->timeSent) * (PPTP_XMIT_WIN - (index + 1)));
```

`index` is bounded only by the window invariant
`xmitSeq - recvAck <= xmitWin <= PPTP_XMIT_WIN(16)`, which the
read-check-increment at `:490-495` enforces **non-atomically** (the
DF-0596 TOCTOU family: two concurrent xmits both observe diff=15 < 16,
both increment → diff = 17). One well-formed ack (`ack = xmitSeq`)
then passes both sanity checks with

```
index = 17 - 0 - 1 = 16
PPTP_XMIT_WIN - (index + 1) = 16 - 17 = -1
sizeof(pptptime_t) * (-1)    = (size_t)0xFFFFFFFFFFFFFFF8
```

→ `bcopy()` of ~2^64 bytes: unbounded OOB read *and* write →
non-recoverable page fault in the kernel (certain panic), plus total
corruption of everything after `timeSent[]` in `priv` before the fault
lands. This is a **distinct sink at a distinct line** from DF-0596's
recorded primitive (the 8-byte OOB write at `:514`), and it corrects
DF-0596's impact ceiling ("~200 bytes remaining in the priv chunk,
limited"): with index ≥ 16 the copy length is not 8 bytes — it is
effectively infinite. Any xmitSeq-recvAck ≥ 17 (however produced)
converts one ordinary ack packet into this.

`bcopy_demo.c` (run in-guest, `run.log`) reproduces the exact kernel
expression and prints the length:

```
recvAck=100 xmitSeq=117 ack=117 -> index=16
int length  = PPTP_XMIT_WIN - (index+1) = -1
size_t len  = sizeof(pptptime_t) * (-1) = 0xfffffffffffffff8
kernel timeSent[] = pptptime_t[16] (128 bytes), index 16 is 8 bytes past end
```

(The `--bcopy` userspace attempt does not fault because glibc's
memcpy end-pointer arithmetic wraps modulo 2^64; the kernel's bcopy
walks forward through unmapped memory and faults — either way the
observation is the length computation, which is identical in kernel
and userspace.)

## Reachability

Requires the DF-0596 TOCTOU (or any equivalent window-violation race)
first — single-threaded, the invariant holds and index ≤ 15
(`recvAck` only grows; stale-read analysis in the audit shows the
recv-side alone cannot exceed 15). The TOCTOU needs two GRE packets in
`ng_pptpgre_recv`/`xmit` on two CPUs — blocked from userspace ng_socket
by the CPU-0 netisr serialization (DF-0590 §2), open in the
ng_ether/SMP VPN-concentrator deployment. The remote peer then only
needs to send the ack for the highest outstanding sequence number —
`cid` must be known (legit session peer, or the DF-0596-noted 65536
brute).

## Fix

Bounds-check `index` before use (defense in depth, independent of
DF-0596's serialization fix):

```diff
--- a/sys/netgraph/pptpgre/ng_pptpgre.c
+++ b/sys/netgraph/pptpgre/ng_pptpgre.c
@@ -649,6 +649,11 @@
 		if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0)
 			goto badAck;		/* ack already timed out */
+		if (ack - priv->recvAck - 1 >= PPTP_XMIT_WIN)
+			goto badAck;		/* window invariant violated */
 		priv->recvAck = ack;
```

plus the per-node serialization fix (DF-0590's recommendation) so the
invariant cannot break in the first place.

## Files

* `bcopy_demo.c`, `run.log` — arithmetic reproduction (in-guest)

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

(No fix.diff for this item: documented recommendation only - see Fix above.)
