β¬’ 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 714 B ↓ raw
build.sh build-script N/A (source-only) 61 B view raw
run.sh run-script N/A (source-only) 87 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 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)