ichsmb_bread returns the raw slave-controlled block count (up to 255) while writing at most 32 bytes β /dev/smb SMB_BREAD then copies out up to 223 bytes of uninitialized kernel stack
Summary
The success path bcopies only min(block_count,*count) but returns the RAW slave count (0..255 from ICH_D0): smb.c clamps the user rcount (up to 1024) to that byte and copyouts from the 1024B stack buf of which <=32 were written - a count=255 slave yields 223 stale kernel-stack bytes (pointers/return addresses) in userspace. Same class as amdsmb DF-1091 and smb.c DF-4990. Fixed module built and run live on the first-ever-live ichsmb rig (q35+ipmi-bmc-sim); stock QEMU clamps hostile counts so the leak was modeled (exact epilogue arithmetic demonstrated) not manifested. min(block_count,32) clamp fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5457 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| df5457_poc.c | β | 7.8 KB | view raw | |
| baseline_run.log | β | 1.9 KB | view raw | |
| fixed_run.log | β | 1.5 KB | view raw | |
| fix.diff | β | 7.2 KB | view raw | |
| README.md | β | 2.4 KB | β raw | |
| VERDICT.md | β | 2.9 KB | β raw | |
| env.txt | β | 496 B | view raw | |
| qemu_cmdline.txt | β | 392 B | view raw |
DF-5457 PoC β ichsmb_bread returns the raw slave-controlled block count (up to 255) while writing at most 32 bytes: kernel stack disclosure via /dev/smb SMB_BREAD
Root cause
On successful block read ichsmb_bread does (ichsmb.c:439-442):
if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
bcopy(sc->block_data, buf, min(sc->block_count, *count)); /* <=32 bytes */
*count = sc->block_count; /* raw slave byte, up to 0xFF */
}
sc->block_count comes from the slave-supplied count register ICH_D0
(ichsmb.c:574-576) with no clamp (the write side of that is DF-1076 β known,
excluded here). The returned count violates the SMB_MAXBLOCKSIZE(=32) driver
contract. smbioctl then does (smb.c:327-329):
if (s->rcount > bcount) s->rcount = bcount; /* up to 255 */
error = copyout(buf, s->rbuf, s->rcount); /* buf = 1024-byte kernel stack array */
buf (smb.c:211 char buf[SMB_MAXBLOCKSIZE] with SMB_MAXBLOCKSIZE=1024,
smb.h:62) had at most 32 bytes initialized by the bcopy, so a slave that
reports count=255 while the user (root) requests rcount=1024 gets
up to 223 bytes of uninitialized kernel stack copied to userspace.
Sibling of DF-1091/DF-2330 (amdsmb, same defect class, Medium) and
DF-4990 (smb.c SMB_TRANS variant).
Live status on this rig
The kernel-side path is fully live (first ichsmb hardware in this audit):
real SSIF block reads work through ichsmb_bread on the q35 rig
(baseline_run.log / fixed_run.log). The >32 precondition cannot be produced
by the stock QEMU: smbus_read_block() clamps a slave count larger than the
32-byte buffer to 0 (hw/i2c/smbus_master.c, QEMU 7.2:
if (rlen > len) { rlen = 0; }), verified empirically (i2c-ddc at 0x50
returns a 0xFF count byte at offset 1 β reads come back count=0/timeout, and
the container has no toolchain to build a patched QEMU). A malicious slave
(patched QEMU per DF-1076's malicious_slave_qemu_patch.txt sketch, or an
ATtiny on the bus) supplies the precondition directly.
The in-guest model mode reproduces the smb.c epilogue arithmetic exactly:
count_in=32 initialized, copyout length 255 β 223 stale-stack bytes (0xAA
pattern) verified to reach the "userspace" buffer.
Build & run
guest: cc -O0 -o /root/df5457_poc /root/df5457_poc.c && /root/df5457_poc model
Fix
ichsmb.c: *count = min(sc->block_count, 32); (and clamp the bcopy the same
way) β included in fix.diff (validated module build, -Werror clean).
DF-5457 VERDICT β NOT REPRODUCED on the available rig (emulator clamps the hostile count); kernel-side path proven live; sink confirmed by trace + model
Bottom line
The unclamped count return at ichsmb.c:441 (*count = sc->block_count,
slave-controlled 0..255) is real and reachable β the block-read path it sits
on was exercised live end-to-end on the q35/ipmi-bmc-sim rig (first live
ichsmb hardware in this audit; real SSIF block reads returned real IPMI
bytes). The leak manifestation needs a slave that reports count>32; stock
QEMU cannot produce one: smbus_read_block() (hw/i2c/smbus_master.c in QEMU
7.2) hard-clamps rlen > len(32) to 0, verified empirically with i2c-ddc
(its EDID has 0xFF at offset 1, so an SMB_BREAD cmd=1 would deliver
count=0xFF on real hardware β on QEMU it yields count=0/timeout instead).
The container hosting this audit has no C toolchain, so a patched QEMU
(DF-1076's malicious_slave_qemu_patch.txt sketch) could not be built. On a
malicious-peripheral threat model (the same precondition DF-1076 was filed
under, High) the arithmetic is deterministic: smb.c:327-329 clamps the user's
rcount (up to 1024) to bcount (up to 255) and copyouts from the 1024-byte
stack buf of which only <=32 bytes were written (model mode: 223 stale-stack
bytes propagate, 0xAA verified).
Caveat on ordering: with count>32 the ISR first OOB-writes block_data (DF-1076, known), smashing sc->mutex; whether the system survives long enough to reach the copyout is timing/config dependent (INVARIANTS-free kernels more likely to survive) β the leak is the read-side consequence of the same primitive, priced accordingly (Medium, like amdsmb DF-1091).
What was verified live
- ichsmb attach + full block-read transaction on real (emulated) ICH9 SMBus:
BREAD cmd=3 β rc=0 rcount=3 data=06 18 00(fixed_run.log; baseline module reaches the same code, only the uninitialized *count gate of DF-5458 masks it). - QEMU clamp behavior: i2c-ddc block reads return count=0 (QEMU truncation), never 0xFF.
modelmode output (baseline_run.log): copyout=255, initialized=32, stale=223.
Fix
ichsmb.c bread success path: *count = min(sc->block_count, 32); and bcopy
bounded the same β in fix.diff (module rebuilt in-guest, -Werror clean, and
the clamped return observed live: every returned rcount <= 32 in
fixed_run.log).
Kernel references
sys/bus/smbus/ichsmb/ichsmb.c:440-441 (sink), :574-576 (source of count, known DF-1076), :64 (block_data[32]); sys/dev/smbus/smb/smb.c:211,318-330 (1024-byte stack buf + min(rcount,bcount) copyout), smb.h:62 (1024 clamp).
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
fixedLeak itself could not be triggered on the rig (QEMU clamps slave counts), so no baseline-vs-patched leak observation is possible; the clamp fix is compiled into the validated module build (DF-5459/DF-5458 packs) and every observed returned count with the fix is <=32.
fix.diff; fixed_run.log (rcount=3 <= 32 on all reads)
Confirmed kernel references
Detail
Exploit chain
malicious SMBus peripheral (patched QEMU / ATtiny on the bus, per DF-1076's threat model) answers a block read with count=0xFF and streams bytes -> ichsmb ISR stores OOB (DF-1076) and sets block_count=255 -> ichsmb_bread bcopy()s only min(255, count_in<=32) bytes but returns *count=255 -> smbioctl clamps the root user's rcount (1024) to 255 and copyouts 255 bytes from the 1024-byte stack buf -> ~223 uninitialized kernel-stack bytes reach userspace (pointers/return addresses).
Evidence (decisive lines)
README.md (trace with exact lines), baseline_run.log model section (copyout=255 init=32 stale=223), fixed_run.log (live block reads through the exact code path; clamped counts after fix), VERDICT.md (QEMU clamp analysis + empirical DDC result)
PoC changes
wrote df5457_poc.c 'model' mode reproducing the smb.c epilogue arithmetic in-guest; live rig work proves the path and the QEMU blocker
Verified recommended fix
ichsmb.c:441: *count = min(sc->block_count, 32); (and bound the bcopy identically); defense in depth: smb.c re-clamp rcount to 32 for SMB_BREAD.
Verdict
NOT REPRODUCED on this rig β not because the kernel path is dead but because the precondition (slave reports block count > 32) cannot be generated by stock QEMU: smbus_read_block clamps rlen>32 to 0 (hw/i2c/smbus_master.c, QEMU 7.2.22), verified live with i2c-ddc (EDID offset 1 = 0xFF would give count=255 on real HW; QEMU returns 0), and this container lacks a C toolchain to build the patched QEMU from DF-1076's sketch. The kernel-side sink is real and its surrounding path is fully live on the q35/ipmi rig (real SSIF block reads; first live ichsmb in this audit). Trace + in-guest model: smb.c:327-29 copyout of min(rcount<=1024, bcount<=255) bytes from a 1024-byte stack buffer of which <=32 are initialized => up to 223 bytes of kernel stack disclosed to a root/local reader when a malicious slave lies about count. Sibling of amdsmb DF-1091 (Medium). Fix (clamp *count to 32) built and validated module-side; with the fix every observed returned count is <=32 (fixed_run.log).
No comments yet.