β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-1862

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 netlink DCB_CMD). Currently no such path exists in if_ix.c (verified by rg: if_ix.c invokes no ixgbe_dcb_* symbol).
  • Privileges gained or impact:
  • OOB kernel-heap read of up to (max_tc - 7) * 4 bytes past hw->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_tcs set > 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.

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1862 Β· 4 files
FileTypeDescriptionSize
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
VERDICT.md verdict source-confirmation analysis
↓ download 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

fixed
baseline reproduced→ patch + rebuild →patched clean

fix.diff compiled in batch kernel build rc=0 -Werror

fix.diff compiled in batch kernel build rc=0 -Werror
↓ fix.diffcombined build rc=0

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)