# DF-3670 — ixgbe_calc_eeprom_checksum_generic: NVM pointer/length walk lacks upstream bounds, u16 index wrap

**File:** `sys/dev/netif/ix/ixgbe_common.c` · **Severity:** Low · **Class:** missing-upstream-fix / NVM-trust correctness

## Defect

`ixgbe_calc_eeprom_checksum_generic()` (ixgbe_common.c:2211-2262) walks
EEPROM sections whose `pointer` (2233) and `length` (2242) are read **from the
NVM itself**, using a `u16 j` loop index:

```c
u16 j;                                        /* 2214 */
...
for (j = pointer + 1; j <= pointer + length; j++)   /* 2250 — u16 wrap */
        hw->eeprom.ops.read(hw, j, &word);
```

There is no check that `pointer < word_size` or that
`pointer + length < word_size`. With `word_size` derived from the
hardware-reported `EEC.SIZE` field (ixgbe_common.c:1277-1280 — up to
`1 << (15 + IXGBE_EEPROM_WORD_SIZE_SHIFT)`), a crafted/corrupted NVM (or a
NIC reporting a large EEC.SIZE) makes the walk wrap `j` at 65536 and traverse
unintended words; the checksum is then computed over the wrong set
(`checksum = IXGBE_EEPROM_SUM - checksum`, 2259). Consumers:

- attach-time validation `ixgbe_validate_eeprom_checksum` (if_ix.c:615) —
  wrong pass/fail decision from crafted NVM (NIC disabled or bad NVM accepted),
- `ixgbe_update_eeprom_checksum_generic` (2320) writes the wrong value into
  NVM word 0x3F — persistent NVM corruption (not called by if_ix.c, exposed
  via ixgbe_api for fw-update paths).

## Upstream divergence (proven)

FreeBSD's copy of this shared code added exactly these bounds and widened `j`
(function-level diff against FreeBSD head `sys/dev/ixgbe/ixgbe_common.c`,
performed during this audit):

```diff
 		if (pointer == 0xFFFF || pointer == 0)
 			continue
+		if (pointer >= hw->eeprom.word_size) {
+			DEBUGOUT("EEPROM pointer outside word range\n");
+			return IXGBE_ERR_EEPROM;
+		}
 		...
 		if (length == 0xFFFF || length == 0)
 			continue
+		if (length >= hw->eeprom.word_size - pointer) {
+			DEBUGOUT("EEPROM section outside word range\n");
+			return IXGBE_ERR_EEPROM;
+		}
-		for (j = pointer + 1; j <= pointer + length; j++) {
+		u32 j; ... word_end = (u32)pointer + length;
```

DragonFly (2017 shared-code snapshot) is missing that fix.

## PoC / verification

Hardware-gated (NVM contents + attach path). No runnable PoC; guest has no
ixgbe device (`env.txt`). `fix.diff` mirrors the upstream bounds and was
compile-validated on the guest's md5-identical `/usr/src`
(`build_patched.log`, `-Werror` clean).
