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

Latent stack OOB in oce_mbox_eqd_modify_periodic: protocol array delay[8] filled from set_eqd[OCE_MAX_EQ=32] with num<=neqs

Summary

The mailbox protocol struct holds delay[8] but the periodic EQ-delay path fills it from set_eqd[32] with num up to sc->neqs - writing past delay[8] (and past the 59-dword mbx payload) if neqs ever exceeds 8. Unreachable today: MSI-X allocation is #if 0'd forcing neqs=1; even re-enabled the bound is exactly 8. Any future raise of OCE_MAX_RSS/OCE_MAX_WQ past 8 turns this into a kernel stack overflow on the 1 Hz periodic path. Clamp-at-protocol-max fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4131 Β· 3 files
FileTypeDescriptionSize
README.md β€” 2.9 KB ↓ raw
verdict.json β€” 2.2 KB view raw
hw_absent.log β€” 64 B view raw

DF-4131 β€” latent stack OOB in oce_mbox_eqd_modify_periodic: delay[8] vs set_eqd[OCE_MAX_EQ=32]

File: sys/dev/netif/oce/oce_mbox.c:1786-1795, 1933-1940; callers oce_if.c:1872-1930 Pass 2 (GLM 5.3), 2026-09-18. Info/hardening: a real array-size mismatch that is NOT reachable under any current DragonFly configuration β€” filed so it cannot become an overflow the day queue scaling is raised.

THE MISMATCH The mailbox command struct holds 8 EQ-delay entries:

    struct mbx_modify_common_eq_delay {           /* oce_hw.h:1786 */
            struct mbx_hdr hdr;
            union {
                    struct {
                            uint32_t num_eq;
                            struct { uint32_t eq_id, phase, dm; }
                                   delay[8];
                    } req;
                    ...
            } params;
    };

but oce_mbox_eqd_modify_periodic() fills it from a caller array sized
OCE_MAX_EQ = 32 (oce_if.h:140):

    struct oce_set_eqd set_eqd[OCE_MAX_EQ];       /* oce_if.c:1872 */
    ...
    oce_mbox_eqd_modify_periodic(sc, set_eqd, num);   /* :1930 */
    ...
    for (i = 0; i < num; i++) {                  /* oce_mbox.c:1934 */
            fwcmd->params.req.delay[i].eq_id = ...   /* OOB when i>7 */

num is bounded by sc->neqs, which counts created event queues.

REACHABILITY ANALYSIS (why Info, not Low) * DragonFly as shipped: MSI-X allocation is #if 0'd out in oce_setup_intr (oce_if.c:604-628) => use_intx=1 => intr_count=1 => exactly one EQ => neqs=1. num<=1. No overflow. * If the #if 0 MSI-X block is re-enabled: intr_count = MAX(nrqs-1, nwqs); nrssqs is MIN(...,OCE_MAX_RSS=8) (oce_mbox.c:2125-2130) and nwqs is MIN(...,OCE_MAX_WQ=8) (oce_mbox.c:2121) => intr_count<=8 => neqs<=8 == delay[8] β€” exactly at the boundary, still no overflow. * The 32-entry caller array therefore always over-describes the 8-entry protocol struct; any future bump of OCE_MAX_RSS/OCE_MAX_WQ past 8 turns this into a kernel stack overflow inside struct oce_mbx on the periodic-EQ-delay path (1 Hz timer), with eq_id/dm values as content.

FIX (defense in depth) #define OCE_MAX_EQ_MBXE 8 / protocol: mbx_modify_common_eq_delay.delay[] / ... if (num > OCE_MAX_EQ_MBXE) num = OCE_MAX_MBXE; / or device_printf + return /

in oce_mbox_eqd_modify_periodic(), or size delay[OCE_MAX_EQ] if the
firmware protocol permits larger num_eq (it does not: 8 is the
documented maximum).

VERDICT not_reproduced: unreachable on DragonFly today (neqs==1 forced by the disabled MSI-X path; even re-enabled it is boundary-exact at 8), and no OCE hardware exists on the audit guest anyway (hw_absent.log). Filed as hardening so the latent mismatch is closed at the source.

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

not runtime-testable: path requires OCE hardware and a configuration (neqs>8) that DragonFly cannot reach as shipped

hw_absent.log + reachability analysis
per-fix-DF-4131

Confirmed kernel references

Detail

Evidence (decisive lines)

hw_absent.log (no OCE hardware on the audit guest); reachability analysis in README.md citing oce_if.c:604-628, oce_mbox.c:2121-2130

PoC changes

no seed; source analysis (unreachable by construction on this tree/guest)

Verified recommended fix

clamp num to the protocol bound 8 (delay[8]) at the top of oce_mbox_eqd_modify_periodic

Verdict

Latent array mismatch: oce_mbox_eqd_modify_periodic fills mbx_modify_common_eq_delay.delay[8] from a caller array sized OCE_MAX_EQ=32 with num<=sc->neqs (oce_mbox.c:1933-1940, oce_if.c:1872/1930). Unreachable on DragonFly today β€” MSI-X is #if 0'd (oce_if.c:604-628) forcing intr_count=1 => neqs=1, and even with MSI-X re-enabled intr_count<=MAX(nrqs-1<=8, nwqs<=8)=8 == delay[8] exactly. Any future raise of OCE_MAX_RSS/OCE_MAX_WQ past 8 converts it into a kernel stack overflow on the periodic timer path. Info-severity hardening: clamp num to 8 (the protocol maximum) at the mailbox boundary.