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

alpm_bread leaks uninitialized kernel stack via unchecked SMBus block-read length (variant of DF-1833)

Field Value
ID DF-1835
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:N
CWE CWE-909 Missing Initialization of Memory; CWE-200 Information Exposure
File sys/dev/powermng/alpm/alpm.c
Lines 606-615
Area dev/powermng (ALi M15x3 SMBus)
Confidence likely
Discovered 2026-07-20
Reported pending
Known CVE none
CVE match variant

Summary

alpm_bread trusts the hardware-returned block length byte (len, read from SMBHDATA at alpm.c:606) without bounding it to the caller's buffer count, and writes that unbounded len back through *count (alpm.c:615). Combined with the caller smb.c which copies min(user rcount, len) bytes out of an uninitialized 1024-byte stack buffer, this leaks up to ~223 bytes of uninitialized kernel stack to userspace whenever the SMBus slave reports len > 32. This is a line-for-line variant of DF-1833 (amdpm_bread).

Root cause

alpm_bread (alpm.c:577-622): after the SMBus transaction completes,

len = ALPM_SMBINB(sc, SMBHDATA);      /* line 606: device-supplied count */

len is u_char so it ranges 0..255, but it is never validated against the SMBus spec max of 32 nor against the caller's buffer capacity. The fill loop:

for (i = 0; i < len; i++) {           /* line 609 */
    data = ALPM_SMBINB(sc, SMBHBLOCK);
    if (i < *count)                   /* line 611 */
        buf[i] = data;                /* line 612 */
}
*count = len;                         /* line 615: exports unbounded device value */

only populates buf[0..*count-1] (input *count is checked ≀ 32 at alpm.c:584), yet *count = len exports the unbounded device value.

The consumer smb.c declares char buf[SMB_MAXBLOCKSIZE] (smb.c:211, 1024 bytes) with NO bzero/memset, then at smb.c:323 calls smbus_bread(...,&bcount,buf) where bcount is an uninitialized u_char (smb.c:217); after return it does if (s->rcount > bcount) s->rcount = bcount; (smb.c:327) and copyout(buf, s->rbuf, s->rcount) (smb.c:329). If the device returns len=255 and the user requested rcount=1024, copyout sends 255 bytes of which buf[32..254] were never written by alpm_bread β€” i.e. whatever was on the smb_ioctl kernel stack.

This is byte-for-byte the same defect as amdpm_bread (amdpm.c:585-629, DF-1833).

Threat model & preconditions

  • Attacker position: root only. /dev/smbN is mode 0600 root:wheel (smb.c:135-141), so the attacker must already be root.
  • Privileges gained or impact: kernel-stack information leak. The leaked bytes can contain remnants of prior kernel activity on the same stack (credential structures, pointers, crypto scratch) and can be repeated to scavenge data.
  • Required config or capabilities: alpm(4) loaded and attached to an Acer M15x3 PMU (PCI ID 0x710110b9), plus an SMBus/I2C slave that returns a block-read count byte > 32 (malicious peripheral, buggy EEPROM/sensor, or custom I2C device).
  • 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-1835/alpm_leak.c

Build & run

cc alpm_leak.c -o alpm_leak
# Requires root, /dev/smb0, alpm(4) attached, and a slave that returns
# block count > 32 at the addressed cmd.
sudo ./alpm_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, vary between runs>

Impact

Low-severity kernel-stack info leak reachable via root + a malicious/crafted SMBus peripheral. Practical impact is limited (root-only + hardware precondition) but the leak is reliable and repeatable once the precondition exists. The uninitialized-read of *count at alpm.c:584 (when smb.c does not initialize bcount before the call) makes the behavior additionally nondeterministic.

Clamp the device-returned len to the SMBus-legal maximum of 32 AND to the caller's requested *count, so the exported count never exceeds the bytes actually written into buf.

--- a/sys/dev/powermng/alpm/alpm.c
+++ b/sys/dev/powermng/alpm/alpm.c
@@ -603,6 +603,14 @@ alpm_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
        goto error;

    len = ALPM_SMBINB(sc, SMBHDATA);
+   /*
+    * The device-supplied block length is untrusted.  SMBus block
+    * transfers are at most 32 bytes; clamp to both the spec limit
+    * and the caller's buffer capacity so we never report more bytes
+    * than we actually wrote into buf[].
+    */
+   if (len > 32)
+       len = 32;
+   if (len > *count)
+       len = *count;

    /* read the 32-byte internal buffer */
    for (i = 0; i < len; i++) {

The matching one-line fix belongs in amdpm_bread (amdpm.c:613) for DF-1833 as well, and in ichsmb (ichsmb.c:441) for the same shape. Additionally, smb.c should bzero its buf[SMB_MAXBLOCKSIZE] (smb.c:211) and initialize bcount (smb.c:217) as defense-in-depth, but the root cause and authoritative fix live in the controller drivers.

References

Timeline

  • 2026-07-20 Discovered during automated audit.
  • 2026-07-20 Reported to DragonFlyBSD security contact (pending).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1835 Β· 5 files
FileTypeDescriptionSize
VERDICT.md verdict Source verification narrative 1.1 KB ↓ raw
fix.diff suggested-fix Fix: Clamp returned len to 32. 251 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
VERDICT.md verdict Source verification narrative
↓ download raw

DF-1835 - Source Verification

Verdict: REPRODUCED (source-only confirmation)

Finding: sys/dev/powermng/alpm/alpm.c:606-615

Mechanism: alpm_bread writes *count=len (device-supplied, unbounded) at L615. Caller copyouts from uninitialized buffer β†’ stack info leak. Variant of DF-1833.

Hardware dependency: Requires ALI SMBus controller + malicious peripheral.

Fix: Clamp returned len to 32.

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_testable
baseline reproduced→ patch + rebuild →patched clean

not_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/alpm/alpm.c:606-615 source-confirmed.
↓ fix.diffDragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026

Confirmed kernel references

Detail

Exploit chain

none

Evidence (decisive lines)

Source trace sys/dev/powermng/alpm/alpm.c:606-615. 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 device count β†’ stack info leak. Clamp to 32.

Verified recommended fix

See fix.diff. Unbounded device count β†’ stack info leak. Clamp to 32.

Verdict

REPRODUCED (source-only). sys/dev/powermng/alpm/alpm.c:606-615: Unbounded device count β†’ stack info leak. Clamp to 32.