cardbus_cis: decode_tuple_bar keeps the attacker-controlled 32-bit CIS BAR size (truncated to a negative int) and passes it unchecked as the resource count; 1<<(ffs(0x80000000)-1) = 1<<31 signed-overflow UB also yields a negative count β both beyond DF-1811's ffs(0) case
Summary
The raw CIS 32-bit size field is assigned to an int len with no upper-bound rejection; when the probe reads back 0/0xffffffff (exactly the values the sanity check excludes) the attacker's value survives to resource_list_add: 0xFFFFFFF0 -> count -16; independently 1<<31 overflows to INT_MIN. Negative counts in a cardbus child's resource list are nonsense for every later rman allocation. Hardware-gated (crafted CardBus CIS); harness REPRODUCES all three modes (fix validated -> EINVAL). Reject-len<=0 + masked-probe-zero fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4690 Β· 14 files| File | Type | Description | Size | |
|---|---|---|---|---|
| cardbus_harness.c | β | 7.2 KB | view raw | |
| build.sh | β | 85 B | view raw | |
| run.sh | β | 109 B | view raw | |
| fix_validate.sh | β | 1.5 KB | view raw | |
| fix4690.diff | β | 626 B | view raw | |
| fix4691.diff | β | 722 B | view raw | |
| build.log | β | 577 B | view raw | |
| run.log | β | 922 B | view raw | |
| fix_run.log | β | 2.8 KB | view raw | |
| env.txt | β | 376 B | view raw | |
| fix.diff | β | 626 B | view raw | |
| VERDICT.md | β | 1.9 KB | β raw | |
| manifest.json | β | 764 B | view raw | |
| verdict.json | β | 3.4 KB | view raw |
DF-4690 -- verdict narrative
Claim
decode_tuple_bar keeps the attacker-controlled 32-bit CIS BAR size when the PCI probe
fails (pci_bar == 0 || pci_bar == 0xffffffff, cardbus_cis.c:362) and assigns it to the
INT parameter len (:308) -> values >= 2^31 truncate to negative; independently, a BAR
probing 0x80000000 gives 1 << (ffs(0x80000000)-1) = 1 << 31 (:368) -- signed overflow
UB that manifests as INT_MIN. Both reach resource_list_add(:377) as a NEGATIVE count for
the child's resource list entry.
Reproduced?
YES, decoder-level (verbatim extraction, run on the DragonFly guest; the accepted DF-1811 used the same source-only standard because no CardBus bridge exists on the guest).
- mode 1: cis size field 0xFFFFFFF0, probe 0xffffffff -> count = -16 (0xfffffff0)
- mode 2: probe 0x80000000 -> ffs==32 -> 1<<31 UB -> count = -2147483648 (0x80000000)
- mode 3 (contrast = known DF-1811): masked probe 0 -> ffs(0)-1 UB -> INT_MIN
A negative count in a resource-list entry is nonsense downstream (rman allocation for
the child driver); the realistic ceiling is the card's own driver failing to attach /
resource misbehavior -- hardware-gated, no local or remote trigger. Severity Low.
Fix validation (fix_validate.sh, fix.diff = fix4690.diff)
Baseline: negative counts reach resource_list_add (above). Patched (reject pci_bar==0 after mask [the DF-1811 half] and len<=0 before resource_list_add): all three cases return EINVAL and the captured count keeps its sentinel 0x42424242 -- resource_list_add is never reached. FIXED at decoder level.
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
fixedHarness-level: baseline m1/m2/m3 deliver negative counts into resource_list_add; with fix4690.diff all three return EINVAL and the captured count keeps its sentinel 0x42424242 (never called).
run.log: 'm1: ... probe=0xffffffff -> resource_list_add count = -16 ... NEGATIVE COUNT' and 'm2: ... probe=0x80000000 -> count = -2147483648 ... NEGATIVE'; fix_run.log: 'PATCHED modes 1/2/3 ... count = 1111638594 (0x42424242)' (sentinel intact = resource_list_add never reached).
Confirmed kernel references
Detail
Exploit chain
malicious CardBus card (physical insertion) -> cardbus_do_cis -> decode_tuple_bar/decode_tuple_funce -> negative resource count / stale-byte MAC ivar; no uid0 path
Evidence (decisive lines)
run.log: 'm1: ... probe=0xffffffff -> resource_list_add count = -16 ... NEGATIVE COUNT' and 'm2: ... probe=0x80000000 -> count = -2147483648 ... NEGATIVE'; fix_run.log: 'PATCHED modes 1/2/3 ... count = 1111638594 (0x42424242)' (sentinel intact = resource_list_add never reached).
PoC changes
verbatim extraction of the two decoder bodies (anchors, cardbus_cis.c:258-290/293-385) against minimal newbus/pci stubs (pci_read/write_config probe emulation, resource_list_add capture); added errno.h include after first build failed on EINVAL
Verified recommended fix
After the probe block, reject non-positive sizes (len <= 0 -> EINVAL) and the masked pci_bar == 0 case (the DF-1811 half) before resource_list_add.
Verdict
REPRODUCED at decoder level on the DragonFly guest (verbatim-extracted decode_tuple_bar, cardbus_cis.c:293-385, driven with crafted CIS bytes + emulated PCI probe; the accepted DF-1811 used the same source-only standard since the guest has no CardBus bridge). Beyond DF-1811 (which covers only masked-probe-zero ffs(0)): (mode 1) when the BAR probe reads back 0xffffffff -- exactly the case :362 excludes -- the attacker-controlled 32-bit CIS size field survives, is assigned to the INT len (:308) and passed UNCHECKED as the resource count to resource_list_add (:377): 0xFFFFFFF0 -> count = -16; (mode 2) a BAR probing 0x80000000 gives 1 << (ffs(pci_bar)-1) = 1 << 31 (:368), signed-overflow UB manifesting as INT_MIN -> count = -2147483648. A negative count in a child resource-list entry is nonsense for every later rman allocation of that entry. Hardware-gated (physical CardBus card); realistic ceiling is the card's driver failing to attach / resource misbehavior, not privilege escalation.
No comments yet.