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

Undefined-behavior bit shift zeroes all 32-bit PCI config reads via ACPI

Summary

AcpiOsReadPciConfiguration computes width mask as *Value &= (1 << (bytes * 8)) - 1 with bytes and 1 of type int. For Width=32 this is 1 << 32 which is UB because shift count equals bit-width of int. On x86-64 emitted shl masks count to 5 bits so expression evaluates to (1 << 0) - 1 == 0 and subsequent &= destroys correctly-read value forcing every 32-bit PCI config read through ACPI to return 0. Mask fully redundant for valid widths (pci_cfgregread returns clean u_int32_t). AcpiExPciConfigSpaceHandler performs NO width validation before calling this function. Impact: AML makes incorrect decisions misdetecting PCI devices wrong power-state transitions potential panic. No memory corruption info leak or privilege escalation. [VERIFIED pass2: reproduced - Width 32 AcpiOsReadPciConfiguration masks to 0 via clang 1-lt-lt-32 UB while raw cfgreg reads 0x12378086, Width 16 reads 0x8086; A/B fix-validated]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2372 Β· 8 files
FileTypeDescriptionSize
README.md β€” 1.1 KB ↓ raw
VERDICT.md β€” 1.3 KB ↓ raw
env.txt β€” 145 B view raw
fix.diff β€” 394 B view raw
fixed.log β€” 595 B view raw
run.log β€” 526 B view raw
run.sh β€” 121 B view raw
verdict.json β€” 1.7 KB view raw

DF-2372 - UB bit shift zeroes all 32-bit ACPI PCI config reads

Bug (sys/dev/acpica/Osd/OsdHardware.c:106)

*Value &= (1 << (bytes * 8)) - 1; - for Width=32, bytes==4 and 1 << 32 is UB (shift count == bit width of int). clang on x86-64 emits shl with a 5-bit masked count, so the expression becomes (1 << 0) - 1 == 0 and the correctly-read value is ANDed to zero.

Rig (ACHARNESS kernel, acsim.c op=pciub32)

Calls the REAL in-kernel AcpiOsReadPciConfiguration on 0:0.0 reg 0 at Width 8/16/32 and the raw pci_cfgregread for ground truth.

Baseline result (run.log)

raw pci_cfgregread(0:0.0, reg0, 4 bytes) = 0x12378086
AcpiOsReadPciConfiguration Width=32 -> value 0x0000000000000000   <-- MASKED TO 0
AcpiOsReadPciConfiguration Width=16 -> value 0x0000000000008086   <-- intact
VERDICT: BUG REPRODUCED

Fixed kernel (fix.diff: 64-bit mask)

AcpiOsReadPciConfiguration Width=32 -> value 0x0000000012378086   <-- real value

Build: baseline ACHARNESS #3 / fixed ACHARNESS #7 (build.log). Run: sysctl -w debug.acsim_op=pciub32 then sysctl -n debug.acsim_log.

VERDICT.md
↓ download raw

DF-2372 VERDICT

Status: reproduced (reproduced) Impact: corruption Confidence: certain Attempts: 2

AcpiOsReadPciConfiguration Width=32 masked every 32-bit PCI config read to zero on the live kernel: raw pci_cfgregread(0:0.0, reg 0, 4) = 0x12378086 while the ACPI path returned 0x00000000 (Width=16 intact at 0x8086). Root cause confirmed at OsdHardware.c:106: (1 << (bytes*8)) - 1 with bytes==4 is the UB shift 1<<32, emitted by clang as a 5-bit-masked shl yielding (1<<0)-1 == 0. Fixed kernel (fix.diff: 64-bit mask) returns the real 0x12378086 at Width=32.

Kernel references

Guest

DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #7: Sat Oct 24 00:08:04 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/ACHARNESS x86_64

Fix validation

See fix.diff and README.md for the baseline/fixed A/B outputs (run.log / fixed.log).

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

not_testable
↓ fix.diffper-fix-DF-2372

Confirmed kernel references

Detail

Exploit chain

AML/ACPICA PCI config reads (e.g. _DSM device detection) silently see 0 instead of real config data - firmware decisions and any AML-driven PCI access are corrupted; no direct kernel memory-safety impact

Evidence (decisive lines)

run.log lines 3-6 (Width=32 value 0x0 vs raw 0x12378086); fixed.log line 4 (Width=32 value 0x12378086)

PoC changes

rig op pciub32 written for this batch; no PoC source existed before

Verified recommended fix

see fix.diff

Verdict

AcpiOsReadPciConfiguration Width=32 masked every 32-bit PCI config read to zero on the live kernel: raw pci_cfgregread(0:0.0, reg 0, 4) = 0x12378086 while the ACPI path returned 0x00000000 (Width=16 intact at 0x8086). Root cause confirmed at OsdHardware.c:106: (1 << (bytes*8)) - 1 with bytes==4 is the UB shift 1<<32, emitted by clang as a 5-bit-masked shl yielding (1<<0)-1 == 0. Fixed kernel (fix.diff: 64-bit mask) returns the real 0x12378086 at Width=32.