# VERDICT — DF-4645 (ixgbe posted-mbx size-discipline bypass, twin of DF-4638)

**status: untested · reproduced: 0 · impact: none (latent) · confidence: certain**

## Bottom line

The twin defect exists verbatim: `ixgbe_read_posted_mbx` dispatches to
`mbx->ops.read` with an unvalidated `size` (sys/dev/netif/ix/ixgbe_mbx.c:238),
bypassing the clamp that exists only in `ixgbe_read_mbx`
(ixgbe_mbx.c:55-56); `ixgbe_write_posted_mbx` dispatches to `mbx->ops.write`
unvalidated (ixgbe_mbx.c:266), bypassing the reject that exists only in
`ixgbe_write_mbx` (ixgbe_mbx.c:80-83). The raw ops (`ixgbe_read_mbx_vf`
ixgbe_mbx.c:467-493, `ixgbe_write_mbx_vf` 425-456, `ixgbe_read_mbx_pf`
708-733, `ixgbe_write_mbx_pf` 665-695) trust `size` verbatim; every mailbox
is a fixed 16-word/64-byte window (`IXGBE_VFMAILBOX_SIZE`, ixgbe_mbx.h:40;
`IXGBE_PFMBMEM(vf)=0x13000+64*vf`, ixgbe_type.h:455). A future caller with
`size > 16` would (a) read `msg[i]` OOB from kernel memory into device MMIO
on the write side and (b) spill register writes/reads past the 64-byte window
into the *next VF's* mailbox — cross-VF corruption/disclosure.

## Why untested (honest classification)

1. **No trigger path exists in-tree.** Exhaustive grep over `sys/` proves the
   only reference the ix driver makes to the mbx subsystem is
   `hw->mbx.ops.init_params(hw)` at if_ix.c:535-536; `read_posted` /
   `write_posted` / `ixgbe_read_mbx` / `ixgbe_write_mbx` have **zero callers**
   outside ixgbe_mbx.c (static-proof.txt, steps 1-2). DragonFly's ix driver
   has no SR-IOV/VF support at all (static-proof.txt, step 5: zero vf/iov
   matches in if_ix.c) — unlike igb (DF-4638), where a VF path at least
   exists.
2. **No hardware on the verification guest.** `pciconf -l` shows a virtio-only
   PCI bus — no 82598/82599/X540/X550 device (env.txt). `if_ix` is compiled
   into the kernel ("module already loaded or in kernel") so the code is
   present but dormant: with no device, `ixgbe_init_mbx_params_*` never runs
   and no `struct ixgbe_hw` mbx ops are ever populated or invoked.
3. Additional structural dead-end on the PF side: `ixgbe_init_mbx_params_pf`
   sets `mbx->timeout = 0` (ixgbe_mbx.c:752), and `ixgbe_poll_for_msg`/
   `ixgbe_poll_for_ack` return `IXGBE_ERR_MBX` immediately when timeout==0
   (ixgbe_mbx.c:164-165, 196-197), so `ixgbe_read_posted_mbx` would fail at
   the poll step before ever dispatching `ops.read` — even a hypothetical PF
   caller cannot reach the unvalidated read today.

Because there is no reachable primitive on any current DragonFly system, this
is filed **Info / latent** exactly like its ig_hal twin DF-4638 (which at
least has a live VF code path). No user→root route exists to demonstrate; the
finding documents the API-contract footgun for the day SR-IOV lands or a
ported caller (e.g., an ixv driver) is added.

## Verification that WAS done

- Full-file read of ixgbe_mbx.c (770 lines) + ixgbe_mbx.h + relevant
  ixgbe_type.h register macros; every dispatch/size path traced (see README).
- Exhaustive caller analysis persisted (static-proof.txt).
- Guest environment captured (env.txt): DragonFly 6.5-DEVELOPMENT
  x86_64, kernel with if_ix compiled in, virtio-only PCI, no /dev/ast*, no
  ixgbe device. Guest left clean (no state changed beyond read-only probes).

## Fix

`fix.diff` mirrors the non-posted discipline inside both posted wrappers
(read: clamp to `mbx->size`; write: reject with `IXGBE_ERR_MBX` +
ERROR_REPORT2). Authored against the read-only `sys/` tree, never applied.
A fix-validation kernel build was not performed: the bug has no trigger path
in-tree (see above), so a patched kernel is observationally identical by any
runnable test — fix validation would be theater. fix_status: not_applicable.

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