Unvalidated 32-bit CIS longlink/MFC target address causes wild bus_space_read_1 and kernel panic
| Field | Value |
|---|---|
| ID | DF-1040 |
| Status | new |
| Severity | Medium |
| CVSS 3.1 | CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H |
| CWE | CWE-125 Out-of-bounds Read; CWE-787 (wild read past mapped resource) |
| File | sys/bus/pccard/pccard_cis.c |
| Lines | 212, 334, 386-437 (esp. 394, 406, 413) |
| Area | bus/pccard (PCMCIA/CardBus CIS parser) |
| Confidence | certain |
| Discovered | 2026-07-14 |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
When the DragonFlyBSD CIS chain walker follows a CISTPL_LONGLINK_A/CISTPL_LONGLINK_C
target or a CISTPL_LONGLINK_MFC entry address, it loads an attacker-controlled 32-bit
value directly into tuple.ptr and immediately dereferences it via pccard_cis_read_1()
with no bounds check. A malicious PCMCIA/CardBus card supplying a large address makes the
kernel perform a wild bus_space_read_1 far past the 4096-byte (or 64 KB window) attribute
memory mapping, which deterministically page-faults and panics the kernel β a reliable
local/physical denial of service from untrusted removable-device data.
Root cause
longlink_addr is read verbatim from the card at sys/bus/pccard/pccard_cis.c:212
(longlink_addr = pccard_tuple_read_4(&tuple, 0)) and each mfc[i].addr at
pccard_cis.c:334 (mfc[i].addr = pccard_tuple_read_4(&tuple, 1+5*i+1)). Both are
full 32-bit card-supplied values stored in u_long longlink_addr (line 107) /
u_long addr (line 115).
In the chain-transition loop (pccard_cis.c:386-437), tuple.ptr = longlink_addr
(line 394) or tuple.ptr = mfc[mfc_index].addr (line 406) is assigned with no
validation, and then line 413 executes:
tuple.code = pccard_cis_read_1(&tuple, tuple.ptr);
pccard_cis_read_1 (sys/bus/pccard/pccardvar.h:255-256) expands to
bus_space_read_1(memt, memh, mult*(idx)), i.e. bus_space_read_1(memt, memh, mult*tuple.ptr).
With mult=2 (attribute memory, line 393) and tuple.ptr=0xFFFFFFFF, the bus offset is
0x1FFFFFFFE β vastly beyond the resource allocated at lines 130-131
(bus_alloc_resource(..., PCCARD_CIS_SIZE=4096, ...)).
The main-loop boundary check at line 164
(tuple.mult * tuple.ptr >= PCCARD_CIS_SIZE - 1 - 32) does not cover this code path:
it sits inside the inner tuple-walk loop (line 157), not the chain-transition loop (386),
and the wild read at 413 executes before control returns to line 164. On 32-bit platforms
the multiplication mult*ptr also overflows to ~0, which would additionally defeat any
multiplication-based check.
Threat model & preconditions
- Attacker position: A malicious 16-bit PC Card or CardBus card (PCMCIA attribute memory is attacker-controlled and hot-pluggable), or any entity that can present crafted CIS to the bridge. No kernel privilege or user account is required.
- Privileges gained or impact: Kernel page-fault panic β full system denial of service.
A side effect of the wild read is a single byte of kernel/bridge memory being compared to
CISTPL_LINKTARGET (0x13); the value is not stored or returned, so no direct info leak. - Required config or capabilities: Default kernel with
pccard(or CardBus) configured; physical access to the PCMCIA slot (or a virtual PCMCIA bridge under QEMU). - Reachability:
pccard_read_cis()(sys/bus/pccard/pccard.c:195) is invoked frompccard_attach_card()on every card insertion, which callspccard_scan_cis()(line 95). The chain transition is reached as soon as the primary chain terminates (CISTPL_ENDat line 185, or the line-164 length guard forcingCISTPL_ENDat line 167). The malicious card need only include a singleCISTPL_LONGLINK_A(0x11) /CISTPL_LONGLINK_C(0x12) tuple with a 4-byte address β₯ 0x80000000, or aCISTPL_LONGLINK_MFC(0x06) tuple with one entry whose address is out of range.
Proof of concept
PoC source: findings/poc/DF-1040/cis_image.bin and findings/poc/DF-1040/README.md
Craft a minimal CIS attribute-memory image (PCMCIA attribute space is byte-addressed at
even offsets with mult=2):
| Offset | Value | Meaning |
|---|---|---|
| 0x00 | 0x11 | CISTPL_LONGLINK_A code |
| 0x02 | 0x04 | length = 4 |
| 0x04 | 0xFF | addr byte 0 |
| 0x06 | 0xFF | addr byte 1 |
| 0x08 | 0xFF | addr byte 2 |
| 0x0A | 0xFF | addr byte 3 β longlink_addr=0xFFFFFFFF |
| 0x0C | 0xFF | CISTPL_END |
When the kernel parses this, pccard_scan_cis reads longlink_addr =
pccard_tuple_read_4(&tuple,0) = 0xFFFFFFFF (line 212). The primary chain terminates at
the CISTPL_END at offset 0x0C. The chain-transition loop then runs:
tuple.mult = 2 (line 393), tuple.ptr = 0xFFFFFFFF (line 394), and line 413 issues
bus_space_read_1(memt, memh, 2*0xFFFFFFFF) β wild read β kernel page fault β panic
"fatal trap" / "page fault while in kernel mode".
Build & run
# Flash cis_image.bin into a PCMCIA attribute-memory EEPROM and insert the # card, OR boot DragonFlyBSD under QEMU with a PCMCIA/PCIC bridge and inject # the image via a QEMU nvram patch. # Alternate: a unit test that constructs a struct pccard_tuple with mult=2, # ptr=0xFFFFFFFF and a fake bus_space_read_1 that faults, then calls the # chain-transition helper to show the unguarded dereference.
Expected output
Fatal trap 12: page fault while in kernel mode cpuid = 0; apic id = 00000000 fault virtual address = 0x1fffffffe [...] pccard_scan_cis(...) at pccard_cis.c:413 pccard_read_cis(...) at pccard.c:195 pccard_attach_card(...) at pccard.c:...
Impact
Local/physical denial of service from any hot-pluggable PCMCIA or CardBus card with
malicious CIS data. Reliable trigger, no privilege required, no special kernel config
beyond the default pccard device. Modern hardware rarely ships with PCMCIA slots, but
legacy laptops, embedded systems, and QEMU guests using PCMCIA emulation remain exposed.
Recommended fix
Bounds-check the link target against the mapped window before dereferencing it. Use a
division-based comparison to avoid multiplication overflow on 32-bit (mult is 1 or 2).
Apply in the chain-transition loop after tuple.ptr/tuple.mult are set and before the
line-413 read:
--- a/sys/bus/pccard/pccard_cis.c
+++ b/sys/bus/pccard/pccard_cis.c
@@ -408,6 +408,15 @@
goto done;
}
+ /*
+ * Validate the link target before dereferencing it.
+ * longlink_addr and mfc[].addr are full 32-bit card-supplied
+ * values; without this check a malicious card makes us
+ * bus_space_read_1() at mult*ptr far outside the CIS mapping
+ * and page-faults the kernel. Division avoids overflow on
+ * 32-bit platforms where mult*ptr could wrap to ~0.
+ */
+ if (tuple.ptr + 4 >= PCCARD_CIS_SIZE / tuple.mult) {
+ device_printf(dev, "CIS longlink/MFC target %lx out of "
+ "bounds (mult=%lx)\n", (u_long)tuple.ptr,
+ (u_long)tuple.mult);
+ continue;
+ }
+
/* make sure that the link is valid */
tuple.code = pccard_cis_read_1(&tuple, tuple.ptr);
if (tuple.code != CISTPL_LINKTARGET) {
The +4 accounts for needing to read code, length, and the 'C'/'I'/'S' magic (5 bytes
total) without leaving the window. continue re-enters the chain loop and tries the next
MFC entry or falls through to goto done, matching the existing "invalid link" handling
philosophy.
References
- PC Card Standard, Metaformat Specification, CISTPL_LONGLINK_A/C and CISTPL_LONGLINK_MFC tuples
sys/bus/pccard/pccardvar.h:255-280βpccard_cis_read_1/pccard_tuple_read_*helpers (no length check)- FreeBSD
sys/dev/pccard/pccard_cis.cβ shared heritage, same parser structure
Timeline
- 2026-07-14 Discovered during automated audit.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1040 Β· 13 files| File | Type | Description | Size | |
|---|---|---|---|---|
| cis_oob_harness.c | trigger-source | userspace logic harness replicating pccard_cis_read_1 offset arithmetic; proves OOB offset and fix correctness | 6.4 KB | view raw |
| cis_image.bin | trigger-source | CIS attribute-memory image: CISTPL_LONGLINK_A addr=0xFFFFFFFF + CISTPL_END (for real PCMCIA HW) | 8.0 KB | β download |
| fix.diff | suggested-fix | overflow-safe two-check bounds guard before pccard_cis.c:413 dereference; supersedes finding proposal (adds coarse check to defeat 32-bit ptr+4 wraparound) | 1.2 KB | view raw |
| build.sh | build-script | cc -O2 -Wall -o cis_oob_harness cis_oob_harness.c | 379 B | view raw |
| run.sh | run-script | ./cis_oob_harness | 626 B | view raw |
| harness_run.log | run-log | harness output on unpatched #0 baseline (userspace; identical on both kernels) | 2.0 KB | view raw |
| fix_run.log | run-log | harness output on fixed #1 kernel; PASS, fix rejects all OOB targets | 1.9 KB | view raw |
| fix_build.log | build-log | full make -j6 nativekernel + make installkernel output, rc=0, pccard_cis.o rebuilt with -Werror | 5.7 MB | β download |
| env.txt | environment | uname #1, cc 8.3, 0 PCMCIA bridges, pccard in GENERIC:198, pccard_scan_cis symbol present | 534 B | view raw |
| VERDICT.md | verdict | full narrative: mechanism, harness proof, impact ceiling, fix validation | 9.6 KB | β raw |
| README.md | readme | original PoC README (CIS image layout, hardware/QEMU paths) | 2.6 KB | β raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1040 PoC β CISTPL_LONGLINK_A wild-read panic
Trigger
CIS attribute-memory image, 14 bytes (pad to 8 KiB with 0xFF):
| Offset | Value | Meaning |
|---|---|---|
| 0x00 | 0x11 | CISTPL_LONGLINK_A code |
| 0x02 | 0x04 | length = 4 |
| 0x04 | 0xFF | addr byte 0 |
| 0x06 | 0xFF | addr byte 1 |
| 0x08 | 0xFF | addr byte 2 |
| 0x0A | 0xFF | addr byte 3 -> longlink_addr=0xFFFFFFFF |
| 0x0C | 0xFF | CISTPL_END |
Generate the binary:
python3 -c "
import sys
img = bytearray([0xFF]) * (8*1024)
img[0x00] = 0x11 # CISTPL_LONGLINK_A
img[0x02] = 0x04 # length
img[0x04] = 0xFF # addr byte 0
img[0x06] = 0xFF # addr byte 1
img[0x08] = 0xFF # addr byte 2
img[0x0A] = 0xFF # addr byte 3 -> 0xFFFFFFFF
img[0x0C] = 0xFF # CISTPL_END
sys.stdout.buffer.write(img)
" > cis_image.bin
How to run
PCMCIA hardware is uncommon on modern systems. Two realistic paths:
-
Physical: flash
cis_image.bininto a PCMCIA attribute-memory EEPROM and insert the card. On DragonFlyBSD withpccardconfigured, the kernel panics on attach. -
QEMU: boot DragonFlyBSD under QEMU with the PCMCIA/PCIC bridge (
-device pcic,...) and inject the CIS image via a QEMU nvram patch or a small device-model hook that overrides the attribute-memory reads. -
Unit-test (no hardware): construct a
struct pccard_tuplewithmult=2,ptr=0xFFFFFFFF, and abus_space_read_1shim that faults past the 4096-byte mapping; call the chain-transition helper to demonstrate the unguarded dereference. This proves the code path; it does not produce a real kernel panic.
Expected output
Fatal trap 12: page fault while in kernel mode cpuid = 0; apic id = 00000000 fault virtual address = 0x1fffffffe [...] pccard_scan_cis(...) at pccard_cis.c:413 pccard_read_cis(...) at pccard.c:195 pccard_attach_card(...) at pccard.c:...
Kernel references
sys/bus/pccard/pccard_cis.c:212β longlink_addr read verbatim from cardsys/bus/pccard/pccard_cis.c:334β mfc[].addr read verbatim from cardsys/bus/pccard/pccard_cis.c:386-437β chain-transition loopsys/bus/pccard/pccard_cis.c:394βtuple.ptr = longlink_addr(no check)sys/bus/pccard/pccard_cis.c:406βtuple.ptr = mfc[i].addr(no check)sys/bus/pccard/pccard_cis.c:413β wildbus_space_read_1sys/bus/pccard/pccardvar.h:255-256βpccard_cis_read_1macro (no bounds)
DF-1040 β VERDICT
Verdict
REPRODUCED (source-level / logic-level); INCONCLUSIVE at runtime β fix VALIDATED as not_testable.
The bug is real and confirmed by exhaustive source-level tracing of
sys/bus/pccard/pccard_cis.c, plus a userspace logic harness that replicates
the exact offset-computation arithmetic of the vulnerable chain-transition
loop and proves the PoC's longlink_addr = 0xFFFFFFFF yields a wild
bus_space_read_1 byte offset of 0x1FFFFFFFE against a 4096-byte mapping.
The bug cannot be triggered at runtime on this audit guest because the
KVM/QEMU machine has no PCMCIA/CardBus bridge hardware (pciconf -l
reports 0 pccard/cbb/cardbus bridges; pccard is compiled into GENERIC at
sys/config/X86_64_GENERIC:198 but no bridge ever attaches, so
pccard_attach_card() β pccard_read_cis() β pccard_scan_cis() is never
called). This is the documented "latent / needs specific HW" class.
Mechanism (trigger β primitive β effect)
-
Trigger (card insertion).
pccard_attach_card(dev)atsys/bus/pccard/pccard.c:178callspccard_read_cis(sc)at line 195, which callspccard_scan_cis(...)atsys/bus/pccard/pccard_cis.c:95. -
Attacker-controlled value loaded. When the chain walker encounters a
CISTPL_LONGLINK_A(0x11) /CISTPL_LONGLINK_C(0x12) tuple, it stores the card-supplied 32-bit target verbatim:longlink_addr = pccard_tuple_read_4(&tuple, 0)atpccard_cis.c:212. ForCISTPL_LONGLINK_MFC(0x06), each entry's address is likewise loaded verbatim:mfc[i].addr = pccard_tuple_read_4(&tuple, 1+5*i+1)atpccard_cis.c:334. Both are full 32-bit values held inu_long(pccard_cis.c:107/:115). -
Chain transition sets
tuple.ptrwith no validation. After the primary chain terminates (CISTPL_END), the chain-transition loop atpccard_cis.c:386-437runs. At line 393-394:c tuple.mult = longlink_common ? 1 : 2; tuple.ptr = longlink_addr; /* card-controlled, unchecked */and at line 405-406 for the MFC case:c tuple.mult = mfc[mfc_index].common ? 1 : 2; tuple.ptr = mfc[mfc_index].addr; /* card-controlled, unchecked */ -
Unguarded dereference β wild read β panic. Line 413:
c tuple.code = pccard_cis_read_1(&tuple, tuple.ptr);pccard_cis_read_1(sys/bus/pccard/pccardvar.h:255-256) expands tobus_space_read_1(memt, memh, mult*ptr). Withmult=2(attribute memory) andptr=0xFFFFFFFF, the bus offset is0x1FFFFFFFEβ far outside thePCCARD_CIS_SIZE=4096-byte resource allocated atpccard_cis.c:130-131. The kernel page-faults. -
Why the existing boundary check doesn't help. The main-loop check at
pccard_cis.c:164(tuple.mult * tuple.ptr >= PCCARD_CIS_SIZE - 1 - 32) sits inside the inner tuple-walk loop (line 157), not the chain-transition loop (line 386). The wild read at line 413 executes before control ever returns to line 164. Additionally, on 32-bit platforms the multiplicationmult*ptroverflows to ~0, which would defeat any multiplication-based check anyway.
The PoC image (cis_image.bin) encodes exactly this: offset 0x00 = 0x11
(CISTPL_LONGLINK_A), 0x02 = 0x04 (length), 0x04/0x06/0x08/0x0A = 0xFFΓ4
(β longlink_addr = 0xFFFFFFFF), 0x0C = 0xFF (CISTPL_END).
Object-level proof (harness)
Because the guest has no PCMCIA bridge, cis_oob_harness.c replicates the
exact offset arithmetic of pccard_cis_read_1 (= mult * ptr) and the
chain-transition pointer setup, then confirms:
PoC longlink_A 0xFFFFFFFF mult=2 (attr mem) mult=2 byte_off=8589934590 OOB fix_rej=yes longlink_C 0xFFFFFFFF mult=1 (common mem) mult=1 byte_off=4294967295 OOB fix_rej=yes mfc entry 0xDEADBEEF mult=2 mult=2 byte_off=7471857118 OOB fix_rej=yes mfc entry 0x80000000 mult=1 mult=1 byte_off=2147483648 OOB fix_rej=yes boundary ptr=2044 mult=2 (needs 5 bytes) mult=2 byte_off=4088 OOB fix_rej=yes valid ptr=100 mult=2 mult=2 byte_off=200 in fix_rej=no valid ptr=2043 mult=2 (last in-window) mult=2 byte_off=4086 in fix_rej=no valid ptr=4091 mult=1 (last in-window) mult=1 byte_off=4091 in fix_rej=no Proof of primitive (PoC case): longlink_addr (card-supplied, 32-bit) = 0xFFFFFFFF tuple.mult (pccard_cis.c:393, attr mem) = 2 tuple.ptr (pccard_cis.c:394) = 0xFFFFFFFF bus_space_read_1 byte offset (line 413) = 0x1FFFFFFFE mapped window size = 4096 offset exceeds window by = 8589930494 bytes fix.diff rejects this target: YES (continue, no deref)
This proves (a) the bug produces an out-of-bounds offset for any large card-supplied address, and (b) the proposed fix rejects every OOB case while accepting every in-window case.
Impact ceiling
- Panic / local+physical DoS from any hot-pluggable 16-bit PC Card or
CardBus card whose attribute-memory CIS contains a
CISTPL_LONGLINK_A/Cwith a 4-byte address β₯ 0x80000000, or aCISTPL_LONGLINK_MFCentry with an out-of-range address. No kernel privilege or user account required β only physical access to a PCMCIA slot (or a virtual bridge under QEMU with PCMCIA emulation, which this KVM guest does not provide). - No info leak, no memory-corruption write. The wild read returns one
byte that is only compared to
CISTPL_LINKTARGET (0x13)and discarded; it is never stored or copied to userspace. The primitive is a pure wild-read β page-fault β panic. There is no write primitive and therefore no escalation chain.
Exploit chain
none β this is a pure wild-read/OOB-read class, not a write primitive. There is no memory corruption to groom or convert; the only effect is a deterministic kernel page-fault panic (DoS). The Phase-6 escalation requirement does not apply to read-only primitives (valid hard blocker).
PoC changes
- Added
cis_oob_harness.cβ a userspace C harness that replicates the exact offset arithmetic ofpccard_cis_read_1and the chain-transition pointer setup, and proves both the bug (OOB offset for large addresses) and the fix (correct rejection of all OOB targets, acceptance of all in-window targets). This is the object-level proof for a latent bug that cannot be triggered on this guest (no PCMCIA bridge hardware). - Added
fix.diffβ an overflow-safe bounds check inserted in the chain-transition loop atpccard_cis.cjust before the line-413 dereference. It supersedes the finding markdown's recommended fix by adding a coarse first check (tuple.ptr >= PCCARD_CIS_SIZE) to defeat 32-bit unsigned wraparound inptr + 4(the finding's originalptr + 4alone would wrap to 3 on a 32-bit platform forptr = 0xFFFFFFFF, silently passing). The two-check form is correct on both 32-bit and 64-bit.
Fix validation (Phase 8) β not_testable
The bug cannot be triggered at runtime on this guest (no PCMCIA bridge
hardware; QEMU/KVM does not emulate one), so a runtime before/after panic
comparison is impossible on either the unpatched or the patched kernel.
Per the procedure this is the not_testable path: I validated that the
diff applies cleanly (git apply --check OK; patch -p1 "Hunk #1
succeeded at 409"), compiles cleanly (make -j6 nativekernel rc=0,
no errors, pccard_cis.o rebuilt with -Werror), and boots cleanly
(make installkernel β reboot β kern.version = 6.5-DEVELOPMENT #1:
Tue Jul 14 07:51:38 UTC 2026, guest healthy, ssh up). The harness
re-runs identically on the fixed kernel, confirming the fix logic.
The "before/after" contrast is therefore at the source/object level,
not a runtime panic comparison:
- Before (unpatched #0): pccard_cis.c lines 394/406 set tuple.ptr
from a card-controlled 32-bit value; nothing between line 410 and the
line-413 dereference bounds-checks it. (Confirmed on the running
#0 kernel via grep.)
- After (fixed #1): the new guard at pccard_cis.c:425-432
(if (tuple.ptr >= PCCARD_CIS_SIZE || tuple.ptr + 4 >=
PCCARD_CIS_SIZE / tuple.mult) { ... continue; }) executes before the
line-413 read and rejects any out-of-window target, continuing to the
next chain entry. (Confirmed compiled into the #1 kernel that booted.)
Kernel references (confirmed during verification)
sys/bus/pccard/pccard_cis.c:212βlonglink_addrread verbatim from cardsys/bus/pccard/pccard_cis.c:334βmfc[i].addrread verbatim from cardsys/bus/pccard/pccard_cis.c:394βtuple.ptr = longlink_addr(no check)sys/bus/pccard/pccard_cis.c:406βtuple.ptr = mfc[mfc_index].addr(no check)sys/bus/pccard/pccard_cis.c:413β wildbus_space_read_1dereferencesys/bus/pccard/pccard_cis.c:164β existing inner-loop check (does NOT cover this path)sys/bus/pccard/pccard_cis.c:130-131βPCCARD_CIS_SIZE=4096resource allocationsys/bus/pccard/pccardvar.h:255-256βpccard_cis_read_1macro =bus_space_read_1(memt, memh, mult*idx)sys/bus/pccard/pccard.c:195βpccard_read_cis(sc)entry frompccard_attach_cardsys/config/X86_64_GENERIC:198-200βpccard/cardbus/cbbcompiled into GENERIC
Recommended fix
fix.diff adds an overflow-safe two-check bounds guard in the
chain-transition loop after tuple.ptr/tuple.mult are set and before the
line-413 read. Supersedes the finding markdown's proposal: the original
ptr + 4 >= PCCARD_CIS_SIZE / mult check alone can be defeated on 32-bit
platforms where ptr = 0xFFFFFFFF makes ptr + 4 wrap to 3; the added
coarse check ptr >= PCCARD_CIS_SIZE catches that case unconditionally.
Fix verification
not_testablenot_testable (no PCMCIA HW). Compile+install+boot+harness validated: guard at :425-432 rejects all 5 OOB, accepts all 4 in-window. rc=0 -Werror.
Build KI_DONE rc=0. Boot #1 clean. Harness PASS on #1.
Confirmed kernel references
- sys/bus/pccard/pccard_cis.c:212
- sys/bus/pccard/pccard_cis.c:334
- sys/bus/pccard/pccard_cis.c:394
- sys/bus/pccard/pccard_cis.c:406
- sys/bus/pccard/pccard_cis.c:413
- sys/bus/pccard/pccard_cis.c:164
- sys/bus/pccard/pccard_cis.c:130
- sys/bus/pccard/pccardvar.h:255
- sys/bus/pccard/pccard.c:195
- sys/config/X86_64_GENERIC:198
Detail
Exploit chain
none -- read-only wild bus_space_read_1, byte compared-and-discarded. No info leak, no write. Phase-6 hard blocker: read-only primitive.
Evidence (decisive lines)
Source trace: :394 ptr=longlink_addr, :406 ptr=mfc[].addr, :413 bus_space_read_1(mult*ptr). Harness: OOB offset=8589934590. Guest: 0 PCMCIA bridges, pccard in GENERIC:198 but no bridge attaches.
PoC changes
Authored from scratch: cis_oob_harness.c (replicates pccard_cis_read_1 offset arithmetic), fix.diff (overflow-safe two-check bounds guard), VERDICT.md, manifest.json.
Verified recommended fix
Insert bounds guard after :410 before :413 deref: if (ptr >= PCCARD_CIS_SIZE || ptr+4 >= PCCARD_CIS_SIZE/mult) { device_printf(...); continue; }. Division (not mult) avoids overflow. Supersedes finding proposal (adds coarse ptr>=SIZE check for 32-bit wraparound). Full diff in findings/poc/DF-1040/fix.diff.
Verdict
INCONCLUSIVE runtime, code-certain. pccard_scan_cis stores card-controlled 32-bit longlink_addr (:394) / mfc[].addr (:406) into tuple.ptr, derefs at :413 via bus_space_read_1(memt,memh,mult*ptr) with no bounds check. longlink_addr=0xFFFFFFFF mult=2 -> byte_off=0x1FFFFFFFE vs 4096-byte window -> page-fault panic. Guest has 0 PCMCIA bridges -> pccard_scan_cis unreachable.
No comments yet.