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

Missing upper-bound on BMC-supplied response byte count causes kernel stack OOB read into userspace reply

Summary

ssif_polled_request reads IPMI responses via smbus_bread into 32-byte stack buffer ssif_buf[SMBUS_DATA_SIZE] (line 73). Returned byte count is BMC-controlled and NEVER validated against SMBUS_DATA_SIZE. On ichsmb/amdsmb backends *count = raw BMC byte (0-255, ichsmb.c:441 sc->block_count from ICH_D0 register, amdsmb.c:539 len from SMB_BCNT) NOT clamped to 32. Only check is count<3 (215) and count<SMBUS_DATA_SIZE for middle blocks only (279); neither bounds upper limit. Single-part: len=count-3 at 240 then bcopy(&ssif_buf[3],req->ir_reply,min(req->ir_replybuflen,len)) at 241-242 -- with count=255 copies 252 bytes from &ssif_buf[3], reading 223 bytes past 32-byte stack buffer. Multi-part READ_CONT: bcopy(&ssif_buf[1],&req->ir_reply[len],min(req->ir_replybuflen-len,count-1)) at 292-293 same flaw count up to 255. Leaked stack bytes land in req->ir_reply, ir_replylen=len (304) records inflated length; IPMICTL_RECEIVE_MSG_TRUNC copies up to ir_replylen+1 bytes to userspace via copyout (ipmi.c:448-468) disclosing kernel stack contents (return addresses, saved frame pointers, adjacent locals, potential credential/function pointers -> KASLR bypass). Attacker: compromised or buggy BMC returning block-read count >32 on SMBUS_READ_START or SMBUS_READ_CONT. Precondition: operator group to open /dev/ipmi0. AV:L/AC:H/PR:L, C:H.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2025 Β· 7 files
FileTypeDescriptionSize
VERDICT.md verdict source trace across SSIF + ichsmb + amdsmb; missing count clamp analysis 3.5 KB ↓ raw
fix.diff suggested-fix reject count>SMBUS_DATA_SIZE after each smbus_bread; matches finding proposal 1.0 KB view raw
fix_build.log build-log combined kernel build rc=0, 0 warnings/errors -Werror; ipmi_ssif.c recompiled 1.4 KB view raw
env.txt environment guest uname, cc version, no-ipmi/no-bmc confirmation 405 B view raw
build.sh build-script documents source-only verification (HW-gated) 645 B view raw
run.sh run-script documents no runtime PoC (HW-gated) 256 B view raw
README.md readme status + verification method summary 779 B ↓ raw
README.md readme status + verification method summary
↓ download raw

DF-2025 PoC β€” Missing upper-bound on BMC-supplied response byte count

Status: inconclusive / reproduced=0 β€” HW-GATED (IPMI SSIF needs a BMC + ichsmb/ amdsmb block controller; none present, ipmi.ko not loaded).

Verification method: source trace of sys/dev/misc/ipmi/ipmi_ssif.c:73,76,183,184,240-242 + sys/bus/smbus/ichsmb/ichsmb.c:440-441,575 + sys/bus/smbus/amdsmb/amdsmb.c:533-539. The count returned by smbus_bread is the raw BMC byte count (0..255), never clamped to SMBUS_DATA_SIZE; the SSIF code then indexes the 32-byte stack ssif_buf with it β‡’ kernel stack OOB read / info leak. See VERDICT.md, fix.diff.

Build/run: no runtime PoC (no BMC). fix_build.log proves ipmi_ssif.c compiled with the fix under -Werror rc=0.

VERDICT.md verdict source trace across SSIF + ichsmb + amdsmb; missing count clamp analysis
↓ download raw

DF-2025 β€” Missing upper-bound on BMC-supplied response byte count

Verdict

CONFIRMED (source-trace); NOT REPRODUCED AT RUNTIME β€” HW-GATED. Status: inconclusive, reproduced=0. The bug is real (confirmed by tracing the SSIF layer and both in-tree SMBus block-read backends), but unreachable on this guest: no BMC, no ichsmb/amdsmb block-transfer controller, ipmi.ko not loaded.

Mechanism (confirmed)

ssif_polled_request() reads IPMI responses into a fixed 32-byte stack buffer: - ipmi_ssif.c:73 β€” u_char ssif_buf[SMBUS_DATA_SIZE]; (SMBUS_DATA_SIZE = 32) - ipmi_ssif.c:76 β€” u_char ... count ... (count is u_char, range 0..255) - ipmi_ssif.c:183 β€” count = SMBUS_DATA_SIZE; then smbus_bread(smbus, ..., &count, ssif_buf);

The count returned by smbus_bread is the BMC-supplied byte count and is never validated against SMBUS_DATA_SIZE. The in-tree backends confirm this: - sys/bus/smbus/ichsmb/ichsmb.c:440-441 β€” bcopy(sc->block_data, buf, min(sc->block_count, *count)); *count = sc->block_count; β†’ the buffer copy is capped at min(count,32) so ssif_buf itself is not overflowed, BUT *count is set to sc->block_count, which the ISR takes straight from hardware: ichsmb.c:575 sc->block_count = bus_read_1(io_res, ICH_D0); (a raw 0..255 byte). - sys/bus/smbus/amdsmb/amdsmb.c:533-539 β€” amdsmb_ec_read(sc, SMB_BCNT, &len); ...; *count = len; β†’ likewise returns the raw BMC byte count (0..255), unclamped.

So after smbus_bread returns, count may be up to 255 while only ≀32 bytes of ssif_buf were populated. The SSIF code then indexes ssif_buf using count: - Single-read path ipmi_ssif.c:240-242 β€” len = count - 3; bcopy(&ssif_buf[3], req->ir_reply, min(req->ir_replybuflen, len)); With e.g. count == 200, len = 197, so bcopy reads up to min(replybuflen,197) bytes from &ssif_buf[3] β€” but ssif_buf is only 32 bytes (indices 0..31). Bytes ssif_buf[32..] are kernel stack past the buffer, leaked into req->ir_reply β‡’ returned to userspace. Kernel stack OOB read / info leak. (Same class applies to the multi-part bcopy at lines 291-293.) - A trivially-malicious BMC need only report count > 32.

Note: this is distinct from DF-2024 (write-path underflow). DF-2025 is the read-response path and the defect is a missing upper bound on the trusted count.

Why it is not reproduced on this guest (HW-gate)

Same as DF-2024: no BMC / no ichsmb-or-amdsmb block controller / ipmi.ko not loaded, so smbus_bread is never driven with attacker data from userspace. The threat actor is a malicious or compromised BMC. No escalation chain developed (trigger not reachable from the unprivileged syscall surface on this guest).

PoC changes

None (source-only verification).

Fix (fix.diff)

In sys/dev/misc/ipmi/ipmi_ssif.c, reject count > SMBUS_DATA_SIZE immediately after each smbus_bread (both the READ_START call and the READ_CONT call inside the multi-part loop), treating an oversized count as a malformed response (goto fail), consistent with the existing if (count < 3) short-reply check at line 215. This prevents any subsequent indexing of ssif_buf past its 32-byte bounds. Matches the finding proposal's intent.

Fix validation (Phase 8)

Combined kernel build with all four fixes: rc=0, 0 warnings, 0 errors under -Werror; ipmi_ssif.c recompiled, ipmi.ko relinked (see fix_build.log). HW-gated β‡’ fix_status = not_testable (applies + compiles + traced to close the path; no runtime demonstration possible without a BMC).

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

VALIDATED build. ipmi.ko rebuilds rc=0.

NK_DONE rc=0.
↓ fix.diffcombined build rc=0 -Werror

Confirmed kernel references

Detail

Exploit chain

none (HW-gated). Threat: malicious BMC.

Evidence (decisive lines)

Source trace ipmi_ssif.c:73,76,183,240. Backend ichsmb.c:440-441 sets *count=block_count.

Verified recommended fix

Reject count>SMBUS_DATA_SIZE after each smbus_bread (READ_START and READ_CONT).

Verdict

HW-GATED (no BMC). Source-CONFIRMED. ssif_polled_request reads responses into ssif_buf[32] via smbus_bread which returns BMC byte count (0..255) without clamping. bcopy uses count into 32B stack buffer -> kernel stack OOB read / info leak.