# DF-4795 — VERDICT

**Status: untested (byte-level transmit pattern proven from source; guest
has no SR-IOV igb VF hardware). Severity: Low (kernleak bucket — guest
kernel-stack disclosure to the host PF only). Confidence: certain.**

## Root cause (path:line)

`sys/dev/netif/ig_hal/e1000_vf.c:403` — `u32 msgbuf[E1000_VFMAILBOX_SIZE];`
is never initialized in `e1000_update_mc_addr_list_vf()`. The function
initializes only:

- `msgbuf[0]` (:426-427), and
- `hash_list[0..mc_addr_count-1]` = `msgbuf` bytes `4 .. 4+2*count-1`
  (:429-434), count clamped to 30.

It then sends the **entire 16-word buffer**:
`e1000_write_msg_read_ack(hw, msgbuf, E1000_VFMAILBOX_SIZE)` (:436) →
`mbx->ops.write_posted(hw, msg, size, 0)` (:385) → `e1000_write_mbx_vf`,
which copies `for (i = 0; i < size; i++) E1000_WRITE_REG_ARRAY(hw,
E1000_VMBMEM(0), i, msg[i]);` (`sys/dev/netif/ig_hal/e1000_mbx.c:476-477`)
into the mailbox registers the PF reads. For `count < 30` the tail (up to
50 of 60 payload bytes; count=5 → bytes 14..63 = words 1(partial)..15) is
uninitialized kernel stack transmitted to the host-side PF driver.

Secondary dead-read of the same array: `msgbuf[0] |= …` at :422 reads
`msgbuf[0]` uninitialized (value discarded by :426) — folded into this
finding, no separate transmit.

## Reachability (live path)

Same chain as DF-4794: igb VF devices (`if_igb.c:108,123`) →
`e1000_vfadapt*` (`e1000_api.c:392-397`) → VF op table (`e1000_api.c:510`)
→ `igb_set_multi()` calls `e1000_update_mc_addr_list` with the joined-group
count (`if_igb.c:1304`); group joins need no privilege. Every multicast
update with fewer than 30 groups (the overwhelmingly common case — e.g. a
plain IPv6 host with a handful of solicited-node groups) transmits
uninitialized stack words to the PF.

## Impact

Disclosure of guest kernel-stack residue across the guest→host boundary
(CWE-908 / CWE-457 family). Recipient is the host PF driver (more
privileged than the guest); exposure beyond the PF driver depends on host
behavior (driver logging / mailbox capture). No guest-internal privilege
crossing; no remote exposure (mailbox is VF↔PF only). Severity Low;
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:L/I:N/A:N.

## Evidence

- `run.log` — `mcmsg_demo` (deterministic model of the exact write pattern)
  on the audit guest: `mc_addr_count=5 → uninit stack bytes sent to PF:
  50 of 60`; count=31/128 → 0 (clamp covers the tail only at exactly 30).
- Upstream divergence: FreeBSD current initializes
  `u32 msgbuf[E1000_VFMAILBOX_SIZE] = {};` in
  `e1000_update_mc_addr_list_vf` (cgit.freebsd.org, fetched 2026-09-23).
- `build.log` — fix compile-validation on the guest: BASE_CC_RC=0,
  FIXED_CC_RC=0; guest source verified bit-identical to the audited tree
  (sha256 c0cdce6b…).
- `env.txt` — virtio-only guest, no e1000/VF device ⇒ runtime transmit not
  exercisable (status `untested`, attempts 0).

## Pass-2 kill list for the rest of e1000_vf.c

See DF-4794/VERDICT.md (covers all mailbox sizes vs buffers, hash bounds,
shift-loop termination, wait-loop bounds, NULL-op dispatch, perm_addr
memcpy bounds). Sibling DF-4638 (posted-wrapper size validation) remains
the canonical mbx footgun finding — no in-tree caller from this file
overflows it (sizes 1/2/3/16 against correctly sized buffers).

## Fix

`fix.diff` hunk 1: `u32 msgbuf[E1000_VFMAILBOX_SIZE] = { 0 };`
(git-apply clean; guest compile-validated). Hunk 2 belongs to DF-4794.

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