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)
PoC verification
Evidence pack
findings/poc/DF-2025 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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 |
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.
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_testableVALIDATED build. ipmi.ko rebuilds rc=0.
NK_DONE rc=0.
Confirmed kernel references
- s
- y
- s
- /
- d
- e
- v
- /
- m
- i
- s
- c
- /
- i
- p
- m
- i
- /
- i
- p
- m
- i
- _
- s
- s
- i
- f
- .
- c
- :
- 7
- 3
- s
- y
- s
- /
- d
- e
- v
- /
- m
- i
- s
- c
- /
- i
- p
- m
- i
- /
- i
- p
- m
- i
- _
- s
- s
- i
- f
- .
- c
- :
- 2
- 4
- 0
- s
- y
- s
- /
- b
- u
- s
- /
- s
- m
- b
- u
- s
- /
- i
- c
- h
- s
- m
- b
- /
- i
- c
- h
- s
- m
- b
- .
- c
- :
- 4
- 4
- 0
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.
No comments yet.