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)
PoC verification
Evidence pack
findings/poc/DF-2372 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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.
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
sys/dev/acpica/Osd/OsdHardware.c:96sys/dev/acpica/Osd/OsdHardware.c:104sys/dev/acpica/Osd/OsdHardware.c:106
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_testableConfirmed 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.
No comments yet.