# DF-3332 — VERDICT

**Finding:** `netmap_grab_packets()` (sys/net/netmap/netmap.c:723-760) computes
its loop terminator `k` from the user-writable shared-memory field
`ring->reserved` with a sign error (`k += n` at netmap.c:740 instead of
`k -= n`). `netmap_txsync_to_host()` validates `ring->cur` (netmap.c:851-857)
but nothing validates `reserved`; with `cur < reserved` the computed `k`
(= cur + num_slots + reserved ≥ num_slots) lies outside the range the loop
variable can ever reach (`nm_next()` wraps within [0, num_slots-1]), so
`for (n = kring->nr_hwcur; n != k;)` never terminates.

## Was it reproduced? YES — in a real kernel, with the verbatim function.

Constraint: the netmap subsystem of this DragonFly tree **does not compile**
(netmap_kern.h:747 dereferences `ifnet.if_unused7`, which no longer exists in
sys/net/if_var.h; `sys/conf/files` contains no netmap entries; no kernel
config registers it; no netmap.ko exists in /boot/kernel — `kldload netmap`
fails and `cd /usr/src/sys/net/netmap && make` dies with 15 hard errors,
all `if_unused7`).  This was already established by the earlier evidence
packs of DF-0401/DF-0546/DF-0547/DF-0616 and re-confirmed this run
(env.txt).

The vulnerable loop itself depends only on `ring->cur`, `ring->reserved`,
`nkr_num_slots`, `nr_hwcur`, and `slot[].len/flags` — none of the rotted
machinery.  `df3332_kmod.c` therefore carries the function **verbatim**
(only additions: iteration counter + bail-out for diagnostic mode, both
marked `INSTRUMENTATION`; `m_devget`/`BDG_NMB`/`NETMAP_BDG_BUF_SIZE`/`D`
stubbed — values irrelevant to loop control, the real macros are
bounded/clamped per netmap_kern.h:838-857) and runs it inside a stock
DragonFly 6.5-DEVELOPMENT kernel as a KLD, driven by exactly the ring state
an mmap()ed unprivileged (wheel-group) thread can write:

### Run 1 — diagnostic (mode 0), vulnerable variant (dmesg.txt, run.log)

    df3332: k=1025 lim=1023 nr_hwcur=0 num_slots=1024
    df3332: RESULT iterations=10241 bailed=1 mbufs=0
            (loop WOULD NOT TERMINATE (bailed out))

k=1025 is unreachable by the loop variable (0..1023) — without the
instrumentation bail-out the loop provably never exits.  Each iteration also
executes the unconditional `D()` kprintf of netmap.c:749.

### Run 2 — diagnostic, FIXED variant (`k -= n`) (run.fixed.log)

    df3332: k=1023 lim=1023 nr_hwcur=0 num_slots=1024 [FIXED]
    df3332: RESULT iterations=1023 bailed=0 mbufs=0 (loop terminated)

Exactly the expected 1023 iterations (hwcur 0 → k 1023).  The one-line fix
eliminates the non-termination.

### Run 3 — pure mode (mode 1), vulnerable variant (run.kernelflood.full.log)

`sysctl -n debug.df3332.trigger=1` executed from ssh **never returned**
("NEVER_PRINTS" marker absent after the call; ssh client killed at 25 s).
Observed afterwards:

* load average 0.00 → 0.63+ and climbing (1 of 6 CPUs pegged);
* serial console flooding at ~100 lines/s with
  `grab_packets [153] bad pkt at N len 0` — 40,088 flood lines captured
  (run.kernelflood.full.log; excerpt in panic.txt);
* new ssh logins intermittently stall during banner exchange (three sessions
  timed out, one succeeded) — system-wide degradation;
* `kill -9` cannot be delivered: the thread never returns to user mode, so
  no signal can take effect (definitional for a kernel-mode non-yielding
  loop; the process is still present and spinning — ps attempts themselves
  stalled behind console contention);
* **`shutdown -p now` never completed** — `vm.sh reset` had to force-kill
  QEMU (the spinning thread blocks system shutdown: further proof of the
  DoS severity).

## Exploit chain / impact

Local denial of service by any principal that can open /dev/netmap
(mode 0660 root:wheel per netmap.c:2237 on this vintage; the code lineage is
FreeBSD's netmap.c r257176 where the same loop shipped): one NIOCREGIF
(NETMAP_SW_RING) + mmap + one NIOCTXSYNC → unkillable kernel thread, console
flood, unbounded mbuf allocation variant (lens ≥ 14) exhausts mbufs.
Not a memory-corruption primitive: all slot accesses stay in-bounds
(`n` cycles 0..lim; `slot->len` checked against 14..NETMAP_BDG_BUF_SIZE at
netmap.c:748; `BDG_NMB` clamps buf_idx) — impact is purely availability.
The write variant can also corrupt ring accounting (avail/hwcur reset at
netmap.c:865-866 after break), but no privilege boundary is crossed.

## Fix validation

`fix.diff` (one line: `k += n;` → `k -= n;` at netmap.c:740, which also
fixes DF-0358's wrong-slot delivery).  A full fixed *netmap* kernel build is
impossible on this tree (subsystem bit-rot), so validation was done with the
**-DDD3332_FIXED variant of the same verbatim function inside the same real
kernel**: non-termination eliminated (Run 2).  fix_status="fixed" with that
caveat.

## Kernel references

* sys/net/netmap/netmap.c:731-741 — the arithmetic (sign error)
* sys/net/netmap/netmap.c:742-759 — the non-terminating loop
* sys/net/netmap/netmap.c:851-857 — only `cur` is validated, `reserved` never
* sys/net/netmap/netmap.c:1443-1445 — NIOCTXSYNC host-ring dispatch
* sys/net/netmap/netmap_kern.h:196-201 — nm_next() wrap range

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