# DF-3664 VERDICT — bge_nvram_getbyte leaks the NVRAM arbiter on error paths

**Status: INCONCLUSIVE at runtime (no bge hardware — and specifically no
BCM5906 — on the audit guest); source-level CERTAIN (visible asymmetry).**

## Root cause

`bge_nvram_getbyte()` — sys/dev/netif/bge/if_bge.c:544-592 — performs the
NVRAM software-arbitration handshake:

```c
551:  CSR_WRITE_4(sc, BGE_NVRAM_SWARB, BGE_NVRAMSWARB_SET1);       /* REQUEST */
552:  for (i = 0; i < 8000; i++) {
553:      if (CSR_READ_4(sc, BGE_NVRAM_SWARB) & BGE_NVRAMSWARB_GNT1)
554:          break;
555:      DELAY(20);
556:  }
557:  if (i == 8000)
558:      return (1);                  /* BUG #1: request still latched —
                                         no BGE_NVRAMSWARB_CLR1 ever written */
561:  access = CSR_READ_4(sc, BGE_NVRAM_ACCESS);
562:  CSR_WRITE_4(sc, BGE_NVRAM_ACCESS, access | BGE_NVRAMACC_ENABLE);
565:  CSR_WRITE_4(sc, BGE_NVRAM_CMD, BGE_NVRAM_READCMD);
566:  for (i = 0; i < BGE_TIMEOUT * 10; i++) { ... }
574:  if (i == BGE_TIMEOUT * 10) {
575:      if_printf(&sc->arpcom.ac_if, "nvram read timed out\n");
576:      return (1);                  /* BUG #2: SWARB lock STILL HELD and
                                         BGE_NVRAMACC_ENABLE left set */
      }
...
585:  CSR_WRITE_4(sc, BGE_NVRAM_ACCESS, access);        /* paired cleanup */
588:  CSR_WRITE_4(sc, BGE_NVRAM_SWARB, BGE_NVRAMSWARB_CLR1);  /* paired */
```

The success path is **paired** (584-589) — this is the e1000/bnx-audit
discipline the orchestrator asked to verify, and it holds for the normal
path. The two *timeout* paths return without either releasing the
arbitration request or restoring the access register.

## Reachability

`bge_read_nvram()` only proceeds for `sc->bge_asicrev ==
BGE_ASICREV_BCM5906` (if_bge.c:603-604); it is called at attach time by
`bge_get_eaddr_nvram()` (if_bge.c:4977-4985) as the second station-address
source. One NVM read-done or grant timeout during attach therefore leaves
the arbiter held for the driver's whole lifetime.

## Impact

Device-side functional denial of service only: after a timeout (i.e. on
already-malfunctioning hardware) other NVRAM masters — ASF/management
firmware, other agents sharing `BGE_NVRAM_SWARB` — can no longer arbitrate
for the flash, and the NVRAM access window stays enabled. No host
memory-safety impact, no unprivileged trigger. Contrast the bnx sibling
DF-3640 (bnx_reset *never* released, filed Low): bge's defect is strictly
weaker (error paths only), hence Info here.

## Verification attempt (honest)

Audit guest: `pci/if_bge` compiled into the kernel (kldstat -v id 59) but
`pciconf -l` shows `NO_BROADCOM_DEVICE` (virtio-net only) and
`sysctl hw.bge` is an unknown oid — attach never runs, so neither the bug
nor the fix is exercisable. Guest `/usr/src` if_bge.c md5
`f6c2d771384a52775cd4bb399d5dcab1` == audited tree (run.log).

## Fix validation

`fix.diff` adds the missing cleanup on both error paths, mirroring the
paired success-path idiom (restore `BGE_NVRAM_ACCESS`, then
`BGE_NVRAMSWARB_CLR1` + flush read; for the grant-timeout path only the
request drop, since `access` is not yet saved). `git apply --check`
passes against the pristine tree. Runtime baseline-vs-patched comparison
impossible for the hardware reason (fix_status: not_testable).

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