amdpm_bread returns unbounded slave-supplied block count, enabling OOB read and kernel-stack info leak
| Field | Value |
|---|---|
| ID | DF-1833 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:L/I:N/A:L |
| CWE | CWE-130 Improper Handling of Length Parameter Inconsistency |
| File | sys/dev/powermng/amdpm/amdpm.c |
| Lines | 613-622 |
| Area | dev/powermng (AMD 8111 SMBus) |
| Confidence | likely |
| Discovered | 2026-07-20 |
| Reported | pending |
| Known CVE | none |
| CVE match | variant |
Summary
In amdpm_bread, after the SMBus block-read transaction completes, the slave-supplied
count byte is read from HSTDATA into local len (line 613) and blindly written back
to the caller's *count at line 622. The internal buffer-write loop (lines 616-621)
is correctly bounded by the original *count (validated β€ 32 at line 592) via
if (i < *count), but the returned *count = len can exceed both the original
request and the 32-byte hardware FIFO. Callers that trust the returned count β
smb(4) copying from an uninitialized stack buffer, or IPMI SSIF bcopy-ing from a
32-byte stack buffer β read past valid data, leaking kernel stack memory or causing
an in-kernel OOB read.
Root cause
At amdpm.c:613:
len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
This reads the count byte the SMBus slave supplied during the block-read transaction
(the AMD 8111 SMBus controller stores the slave's count in HSTDATA). The FIFO
write loop at lines 616-621 correctly guards buf[i] = data with
if (i < *count) using the original caller-supplied *count (still intact, validated
β€ 32 at line 592):
for (i = 0; i < len; i++) {
data = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO);
if (i < *count)
buf[i] = data;
DELAY(2);
}
*count = len; /* <-- line 622: overwrites caller count with raw HW value */
Since HSTDATA is a u_short and len is a u_char, len can be 0β255. The AMD
8111 FIFO is only 32 bytes, so any len > 32 means: (a) the loop reads stale/garbage
from HSTDFIFO beyond 32 entries (harmless register reads), (b) buf was only
populated up to min(original_count, 32) bytes, but (c) the caller is told len
bytes are valid.
The sibling driver sys/bus/smbus/amdsmb/amdsmb.c:539 has the identical defect, and
ichsmb (sys/bus/smbus/ichsmb/ichsmb.c:441) has the same shape
(*count = sc->block_count).
Threat model & preconditions
- Attacker position: root opening
/dev/smb*(mode 0600, smb.c:136), OR an in-kernel consumer (IPMI-over-SSIF) talking to a malicious/compromised BMC. - Privileges gained or impact:
- Primary userspace path: kernel-stack info leak. An attacker with root privilege
opens
/dev/smb0and issuesSMB_BREADwithrcount=SMB_MAXBLOCKSIZE(1024). If the addressed slave returns a count byte > 32 (a malicious peripheral, buggy EEPROM, or crafted I2C device),amdpm_breadsetsbcountto that value.smb.c:327-329then doess->rcount = min(s->rcount, bcount); copyout(buf, s->rbuf, s->rcount)from an uninitializedchar buf[1024](smb.c:211). Onlymin(original_bcount, 32)bytes were written; the remainder is uninitialized kernel stack leaked to userspace β can disclose kernel pointers (KASLR bypass), stack canaries, or adjacent stack data. - In-kernel path: IPMI SSIF (
ipmi_ssif.c:73declaresu_char ssif_buf[32], passescount=32at line 184) doesbcopy(&ssif_buf[3], req->ir_reply, min(req->ir_replybuflen, count-3))at line 241 β ifamdpm_breadreturnscount > 32, this reads past the 32-bytessif_bufon the IPMI thread's stack. - Required config or capabilities: AMD 8111 SMBus controller (this driver); for
the IPMI path, additionally IPMI-over-SSIF with a compromised/malicious BMC.
Default DFly has no devfs rule granting non-root access to
/dev/smb*. - Reachability: SMBus block-read transaction to a slave that returns a count byte larger than its actual payload.
Proof of concept
PoC source: findings/poc/DF-1833/amdpm_leak.c
Build & run
cc amdpm_leak.c -o amdpm_leak # Slave at addr 0x50 must return a block count > 32 (a malicious peripheral # or crafted I2C device). Root required for /dev/smb0. sudo ./amdpm_leak /dev/smb0 0x50
Expected output
returned rcount=<n> # n > 32 when the slave lies <bytes beyond offset min(orig,32) are leaked kernel stack, non-zero / non-pattern>
For the IPMI-SSIF OOB path no userspace PoC exists; trigger is a BMC that
responds to SSIF READ_START with a block-count byte > 32 while the SMBus
controller is amdpm. ipmi_ssif.c:241 bcopy reads past ssif_buf[32].
Impact
Low-severity kernel-stack info leak reachable via root + a malicious/crafted
SMBus peripheral, or via a compromised BMC in IPMI-SSIF configurations. Default
DFly does not grant non-root /dev/smb* access. The leak can disclose kernel
pointers and stack canaries but is gated behind root and a cooperating slave.
Recommended fix
Clamp the slave-supplied count to the original *count (already validated β€ 32
at line 592) before using it for both the loop bound and the returned count.
This ensures the caller never sees a count larger than the buffer it offered and
the bytes actually written.
--- a/sys/dev/powermng/amdpm/amdpm.c
+++ b/sys/dev/powermng/amdpm/amdpm.c
@@ -610,11 +610,16 @@ amdpm_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
goto error;
len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
+ /*
+ * The slave supplies the count byte; clamp it to the caller's
+ * original request (already validated <= 32) so *count never
+ * exceeds the bytes actually written into buf.
+ */
+ if (len > *count)
+ len = *count;
/* Read the 32-byte internal buffer */
for (i = 0; i < len; i++) {
data = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO);
- if (i < *count)
- buf[i] = data;
+ buf[i] = data;
DELAY(2);
}
*count = len;
The same fix should be applied to:
- sys/bus/smbus/amdsmb/amdsmb.c:533-539 (identical unbounded *count = len)
- sys/bus/smbus/ichsmb/ichsmb.c:441 (same shape *count = sc->block_count)
References
- Sibling defects: amdsmb.c:539, ichsmb.c:441.
- Caller info-leak path: smb.c:211, 327-329 (uninitialized
char buf[1024]). - Caller OOB read path: ipmi_ssif.c:73, 184, 241 (
bcopyfrom 32-bytessif_buf).
Timeline
- 2026-07-20 Discovered during automated audit.
- 2026-07-20 Reported to DragonFlyBSD security contact (pending).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1833 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | Source verification narrative | 1.1 KB | β raw |
| fix.diff | suggested-fix | Fix: Clamp returned len to 32 (SMBus block max). | 259 B | view raw |
| build.sh | build-script | Build/validation instructions | 366 B | view raw |
| run.sh | run-script | Run instructions (HW-gated, source-only) | 184 B | view raw |
| env.txt | environment | Guest environment | 404 B | view raw |
DF-1833 - Source Verification
Verdict: REPRODUCED (source-only confirmation)
Finding: sys/dev/powermng/amdpm/amdpm.c:613-622
Mechanism: amdpm_bread writes *count=len (slave-supplied, unbounded) at L622. Caller copyouts min(rcount,bcount) from uninitialized char buf[1024] β kernel stack info leak.
Hardware dependency: Requires AMD SMBus controller + malicious slave peripheral.
Fix: Clamp returned len to 32 (SMBus block max).
Verification method
Source-only confirmation. The cited code path was traced line-by-line in the audited sys/ tree. The bug exists exactly as described. This is a HW-gated driver finding β the vulnerable code path requires specific hardware (GPU, controller, PHY, TPM, etc.) not present in the QEMU audit guest. Runtime reproduction on this guest is not possible without the hardware.
Fix validation
fix.diff authored and applied to guest source. All 40 fixes in this batch
compile cleanly in a single combined kernel build: make -j6 nativekernel
KERNCONF=X86_64_GENERIC β rc=0, zero -Werror violations.
Kernel: DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026
Fix verification
not_testablenot_testable: HW-gated. fix.diff applies + compiles in batch build (rc=0 -Werror). Source trace confirms fix closes the path.
Batch build: 40 fix.diffs applied, make nativekernel β rc=0 -Werror. Bug at sys/dev/powermng/amdpm/amdpm.c:613-622 source-confirmed.
Confirmed kernel references
- s
- y
- s
- /
- d
- e
- v
- /
- p
- o
- w
- e
- r
- m
- n
- g
- /
- a
- m
- d
- p
- m
- /
- a
- m
- d
- p
- m
- .
- c
- :
- 6
- 1
- 3
- -
- 6
- 2
- 2
Detail
Exploit chain
none
Evidence (decisive lines)
Source trace sys/dev/powermng/amdpm/amdpm.c:613-622. HW-gated (no HW in QEMU). Fix compiles in batch build rc=0.
PoC changes
Evidence pack: VERDICT.md, fix.diff, manifest.json. Fix: Unbounded slave count β stack info leak. Clamp to 32.
Verified recommended fix
See fix.diff. Unbounded slave count β stack info leak. Clamp to 32.
Verdict
REPRODUCED (source-only). sys/dev/powermng/amdpm/amdpm.c:613-622: Unbounded slave count β stack info leak. Clamp to 32.
No comments yet.