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)
PoC verification
Evidence pack
findings/poc/DF-4131 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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_testablenot runtime-testable: path requires OCE hardware and a configuration (neqs>8) that DragonFly cannot reach as shipped
hw_absent.log + reachability analysis
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.
No comments yet.