ixgbe_dcb_config_pfc_82599 uses unbounded u8 map[] to size PFC loop: OOB read + OOB MMIO write (latent)
| Field | Value |
|---|---|
| ID | DF-1862 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:L/I:L/A:H |
| CWE | CWE-125 Out-of-bounds Read; CWE-787 Out-of-bounds Write |
| File | sys/dev/netif/ix/ixgbe_dcb_82599.c |
| Lines | 321-324, 328 |
| Area | dev/netif (ixgbe DCB PFC config) |
| Confidence | certain |
| Discovered | 2026-07-20 |
| Reported | pending |
| Known CVE | none |
| CVE match | dfly_specific |
Summary
ixgbe_dcb_config_pfc_82599 derives max_tc as the max of map[0..7] without
clamping. Because map[] is u8 (0..255) and ultimately traces back to
cfg->num_tcs.pg_tcs (also u8, never validated to <= 8 anywhere), the
subsequent loop for (i = 0; i <= max_tc; i++) runs up to 256 iterations and
(a) reads hw->fc.high_water[i] / hw->fc.low_water[i] OOB (arrays of size 8),
and (b) computes IXGBE_FCRTL_82599(i)/IXGBE_FCRTH_82599(i)/IXGBE_RXPBSIZE(i)
for i >= 8, clobbering adjacent NIC registers.
No path in the current DragonFlyBSD ix driver reaches this function with
attacker-influenced input, so impact is latent β but the symbol is exported and
any future sysctl/ioctl/KLD that wires up DCB CEE config (as Linux does via
netlink) becomes immediately vulnerable.
Root cause
ixgbe_dcb_82599.c:321-324:
u8 max_tc = 0;
for (i = 0; i < IXGBE_DCB_MAX_USER_PRIORITY; i++) {
if (map[i] > max_tc)
max_tc = map[i];
}
with no clamp. Then ixgbe_dcb_82599.c:328:
for (i = 0; i <= max_tc; i++) {
Inside that loop:
- Line 339-341: reads hw->fc.high_water[i] and hw->fc.low_water[i]
(declared u32[IXGBE_DCB_MAX_TRAFFIC_CLASS] at ixgbe_type.h:3787-3788, size 8)
- Line 341/351/354/358/359: writes IXGBE_FCRTL_82599(i)/IXGBE_FCRTH_82599(i)
(ixgbe_type.h:357-358: 0x03260 + ((_i) * 4) β Intel spec defines only 0..7)
- Line 350: reads IXGBE_RXPBSIZE(i)
(ixgbe_type.h:406: 0x03C00 + ((_i) * 4) β only 0..7)
For any map[k] > 7 (e.g. 0xFF), i proceeds 8..255 and all of those accesses
go OOB.
The map[] values originate in ixgbe_dcb.c:263 ixgbe_dcb_get_tc_from_up(),
which initializes u8 tc = cfg->num_tcs.pg_tcs and only decrements; if
pg_tcs > 8 (never validated anywhere), tc_config[tc] is read OOB and a
tc > 7 is returned into map[].
Threat model & preconditions
- Attacker position: a privileged user able to influence
dcb_config(e.g. via a future sysctl/ioctl wiring up DCB CEE config β Linux exposes this via netlinkDCB_CMD). Currently no such path exists inif_ix.c(verified byrg:if_ix.cinvokes noixgbe_dcb_*symbol). - Privileges gained or impact:
- OOB kernel-heap read of up to
(max_tc - 7) * 4bytes pasthw->fc.high_water[]/low_water[], values written to NIC MMIO. - OOB MMIO writes clobber adjacent NIC registers (RT2CR, RT2SR, RXPBSIZE of other TCs, etc.), causing NIC malfunction, link instability, or machine-check/panic on MMIO fault.
- Required config or capabilities: Intel 82599/X540/X550 NIC present;
dcb_config->num_tcs.pg_tcsset > 8 by the configuration source. - Reachability: currently dormant. Any future KLD module or sysctl/ioctl that wires up DCB CEE config becomes immediately vulnerable.
Proof of concept
Currently no in-kernel path on DragonFlyBSD reaches
ixgbe_dcb_config_pfc_82599 with attacker-controlled map[]. Reproduction
requires either:
- (a) loading a custom KLD that calls ixgbe_dcb_config_pfc_82599(hw, 0xFF, map)
with map[0] = 0xFF and observing the resulting OOB MMIO writes, or
- (b) the addition of a sysctl/ioctl in the future that wires up dcb_config.
Classify as a latent hardening bug, not an in-tree exploit.
Impact
Low-severity latent OOB read + OOB MMIO write. Currently dormant (no in-tree path reaches it with attacker input). Any future DCB config wiring (as Linux does via netlink DCB) would activate it.
Recommended fix
Clamp max_tc to the hardware limit before using it as a loop bound.
--- a/sys/dev/netif/ix/ixgbe_dcb_82599.c
+++ b/sys/dev/netif/ix/ixgbe_dcb_82599.c
@@ -318,6 +318,11 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *map)
IXGBE_WRITE_REG(hw, IXGBE_MFLCN, reg);
for (i = 0; i < IXGBE_DCB_MAX_USER_PRIORITY; i++) {
+ /* map[i] is a u8 but must index a MAX_TRAFFIC_CLASS (8) world.
+ * Clamp before using it as a loop bound to avoid OOB reads of
+ * hw->fc.high_water/low_water and OOB MMIO writes.
+ */
+ if (map[i] >= IXGBE_DCB_MAX_TRAFFIC_CLASS)
+ return IXGBE_ERR_PARAM;
if (map[i] > max_tc)
max_tc = map[i];
}
And in ixgbe_dcb.c, harden the upstream source so map[] can never carry an
out-of-range TC:
--- a/sys/dev/netif/ix/ixgbe_dcb.c
+++ b/sys/dev/netif/ix/ixgbe_dcb.c
@@ -264,7 +264,8 @@ u8 ixgbe_dcb_get_tc_from_up(struct ixgbe_dcb_config *cfg, int direction, u8 up)
struct ixgbe_dcb_tc_config *tc_config = &cfg->tc_config[0];
u8 prio_mask = 1 << up;
u8 tc = cfg->num_tcs.pg_tcs;
-
+ if (tc > IXGBE_DCB_MAX_TRAFFIC_CLASS)
+ tc = IXGBE_DCB_MAX_TRAFFIC_CLASS;
/* If tc is 0 then DCB is likely not enabled or supported */
if (!tc)
goto out;
Timeline
- 2026-07-20 Discovered during automated audit.
- 2026-07-20 Reported to DragonFlyBSD security contact (pending).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1862 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | git-apply-able fix for the cited bug | 373 B | view raw |
| VERDICT.md | verdict | source-confirmation analysis | 1.0 KB | β raw |
| build.sh | build-script | N/A (source-only) | 65 B | view raw |
| run.sh | run-script | N/A (source-only) | 89 B | view raw |
DF-1862 VERDICT
Verdict: REPRODUCED (source-confirmed)
Impact: Low (driver-level NULL deref / OOB / leak / DoS β hardware-gated)
Mechanism: ixgbe_dcb_82599.c L321-324 u8 max_tc=0 for(i<8)if(map[i]>max_tc)max_tc=map[i] no clamp. L328 for(i=0;i<=max_tc;i++) up to 256 iters. Inside: L339-341 read hw->fc.high_water[i]/low_water[i] size 8 ixgb
Citation: sys/dev/netif/ix/ixgbe_dcb_82599.c:321-328
Fix: Applied fix.diff β compiles in batch kernel build (rc=0, -Werror).
Verification method: Source-only line-by-line trace of cited path:line. Low-severity driver bug; PoC trigger requires specific hardware or root context. Confirmed the cited vulnerable pattern exists in source.
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.
Fix verification
fixedfix.diff compiled in batch kernel build rc=0 -Werror
fix.diff compiled in batch kernel build rc=0 -Werror
Confirmed kernel references
β
Detail
Exploit chain
none (Low severity)
Evidence (decisive lines)
Source-confirmed: unbounded u8 map[] drives PFC loop past array bounds (ixgbe_dcb_82599.c:321-328)
Verified recommended fix
Source-confirmed: unbounded u8 map[] drives PFC loop past array bounds (ixgbe_dcb_82599.c:321-328)
Verdict
Source-confirmed: unbounded u8 map[] drives PFC loop past array bounds (ixgbe_dcb_82599.c:321-328)
No comments yet.