pccard_function_init partial-allocation retry across CIS config entries panics resource_list_add (crafted evil-card CIS)
Summary
When a CFTABLE_ENTRY partially allocates (first range granted, later refused) the not_this_one jump leaves the busy rle entries in place (the purge is #if 0'd) - the NEXT config entry's resource_list_add hits 'resource entry is busy' panic. Every ingredient (entry count, per-entry ranges, sizes) is card-controlled; crafted tuples parse cleanly so the card->error gate does not help. Deterministic panic at insertion/boot + non-panicking variants leak bridge windows. Guest-model-verified (exact production-path model: exit 42 + 'panic: resource_list_add: resource entry is busy'). Unwind-partial-allocation fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5355 Β· 23 files| File | Type | Description | Size | |
|---|---|---|---|---|
| rig2_main.c | β | 18.2 KB | view raw | |
| rig2_shims.h | β | 13.8 KB | view raw | |
| extract2.sh | β | 8.1 KB | view raw | |
| build.sh | β | 66 B | view raw | |
| run.sh | β | 97 B | view raw | |
| run_matrix.sh | β | 1.9 KB | view raw | |
| run.log | β | 502 B | view raw | |
| fixed_run.log | β | 700 B | view raw | |
| busypanic_pair.log | β | 1.1 KB | view raw | |
| build.log | β | 2.5 KB | view raw | |
| extract2_manifest.txt | β | 2.4 KB | view raw | |
| matrix.log | β | 1.6 KB | view raw | |
| env.txt | β | 323 B | view raw | |
| fix.diff | β | 1.1 KB | view raw | |
| fixes/ | β | 4.0 KB | β download | |
| seed_model/ | β | 4.0 KB | β download | |
| VERDICT.md | β | 5.6 KB | β raw | |
| README.md | β | 1.4 KB | β raw | |
| verdict.json | β | 5.5 KB | view raw | |
| postboot_run.log | β | 16.8 KB | view raw | |
| postboot_extract_manifest.txt | β | 2.4 KB | view raw | |
| kernel_apply.log | β | 231 B | view raw | |
| kernel_build.tail.log | β | 4.6 KB | view raw |
DF-5355 -- pccard_function_init partial-allocation retry panics resource_list_add
Impact: deterministic kernel panic at evil-card insertion/boot
(resource_list_add: resource entry is busy); non-panicking variants hold
bridge windows. Physical-access DoS (16-bit PC Card socket).
Reproduce (verbatim rig -- shared with DF-2318/DF-5356)
# on the DragonFly guest (pristine /usr/src): sh build.sh # machine-extracts production pccard.c/subr_bus.c/cis code ./rig2 busypanic # the DF-5355 scenario sh run_matrix.sh matrix # A/B: baseline vs df5355/df2318/df5356 fix variants
Success criterion (baseline):
pccard0: Allocation failed for cfe 0 RIG KERNEL PANIC: resource_list_add: resource entry is busy RESULT busypanic: exit 42
With the fix (fixed_run.log): exit 0 -- cfe#0 unwinds, cfe#1 gets the window, the function attaches cleanly.
The full rig (all 7 scenarios incl. DF-2318/DF-5356) lives in
../DF-2318/; this pack is a self-contained copy.
Fix
fix.diff (== fixes/df5355.diff): unwind partial allocations at
not_this_one -- release each busy entry's resource, clear rle->res, and
delete it from the list before trying the next config entry. NOTE: this
supersedes the originally-seeded fix, which omitted trle->res = NULL and
itself panicked in resource_list_delete (see VERDICT.md). Validated by rig
A/B + combined-fix kernel boot; never applied to sys/.
DF-5355 -- VERDICT
Verdict in one line
REPRODUCED (verbatim-rig level; deterministic across 3/3 runs) -- impact: panic.
The verbatim production pccard_function_init (sys/bus/pccard/pccard.c:407-503)
leaves a partially-allocated, res-busy resource-list entry when a card config
entry fails mid-way (not_this_one, purge #if 0'd at :499-501); the next
CFTABLE_ENTRY's resource_list_add for the same (type, rid) hits the verbatim
production panic resource_list_add: resource entry is busy
(sys/kern/subr_bus.c:2631). Hardware-gated kernel entry (no PCMCIA bridge in
QEMU -- env.txt), proven on the byte-identical extracted code.
Upgrade over the seeded model
The seeded pack verified this with a hand-written model of the three code
regions. This run replaces the model with the machine-extracted production
code (DF-2319 verbatim-rig protocol): extract2.sh pulls
pccard_function_init, the resource_list_* family and the whole
attach/detach/CIS-parse chain byte-identical from the guest's /usr/src
(sha256-gated: pccard.c 5b610669..., subr_bus.c 949f75de...;
PCCARD_BYTE_IDENTICAL=yes, SUBR_BUS_BYTE_IDENTICAL=yes).
The seeded model is preserved in seed_model/ for provenance; its CIS
encoding knowledge (little-endian addr/len, length+1 semantics) carried over
into the rig's tuple builders.
The reproduced chain (run.log)
CIS: VERS_1 + MANFID + CONFIG + CFTABLE#0(2 io ranges: anywhere + fixed
0x3F8) + CFTABLE#1(1 range: fixed 0x200). Bridge I/O window [0x110,0x2FF]
(what a finite pcic/cbb window decodes; 0x3F8 is a legacy-occupied host range
outside it).
- verbatim
pccard_attach_card-> verbatim CIS parse: both cfe entries decode cleanly (card.error=0-- the gate at pccard.c:205 does not fire). - verbatim
pccard_function_initon cfe#0 (pccard.c:425-451): * iospace[0] start=0 ->bus_alloc_resourcegrants window space ->resource_list_add(rl, IOPORT, rid=0, ...)+rle->res = r(:443-449) * iospace[1] fixed 0x3F8 -> bridge refuses ->goto not_this_one(:441-442) * the purge is#if 0'd (:499-501): rid-0 stays busy in rl * log:pccard0: Allocation failed for cfe 0(verbatim DEVPRVERBOSE) - loop continues to cfe#1: iospace[0] fixed 0x200 -> granted ->
resource_list_add(rl, IOPORT, rid=0, ...)(pccard.c:443) -> verbatim subr_bus.c:2619resource_list_findreturns the busy entry -> :2630-2631if (rle->res) panic("resource_list_add: resource entry is busy") - rig prints
RIG KERNEL PANIC: resource_list_add: resource entry is busy, exit 42 (kernel: system halted at card insertion / boot with card seated).
Every ingredient is card-controlled: the number of config entries, their io-range counts, addresses and lengths are all CFTABLE_ENTRY fields (pccard_cis.c:1023-1098), and the mixed anywhere/fixed request pattern is what real multi-function serial cards present.
Determinism: 3/3 identical (run.log in DF-2318's pack = full 7-scenario run; this pack carries the busypanic scenario logs).
Fix validation
- The SEEDED fix.diff was itself buggy: it called
resource_list_deletewithout clearingrle->res, so the fixed code panicked inresource_list_delete: resource has not been released(first matrix run). Productionpccard_function_freeexplicitly doesrle->res = NULLafter release (pccard.c:534) -- the unwind must too. fix.diff in this pack is the corrected, validated version (addstrle->res = NULL;). - Single-fix A/B (matrix.log / fixed_run.log): busypanic exits 0 -- cfe#0 fails and unwinds, cfe#1 allocates 0x200 cleanly (io-windows-held=1), function attaches, devadded prints the pnpinfo string, zero leak. All six other scenarios unchanged (f5355 variant still crashes no_vers1 = DF-2318, still leaks reentry = DF-5356; controls green).
- Combined three-fix kernel:
-Werrornativekernel rc=0, installed, booted (kernel #1); rig re-extracted from the RUNNING kernel's source and re-driven: busypanic clean (postboot_run.log in DF-2318's pack). Guest reset to clean-source snapshot afterwards.
Kernel references
- sys/bus/pccard/pccard.c:425 (cfe scan loop)
- sys/bus/pccard/pccard.c:429-440 (per-range bus_alloc_resource)
- sys/bus/pccard/pccard.c:443-449 (resource_list_add + rle->res = r)
- sys/bus/pccard/pccard.c:441-442 / :464-465 / :483-484 (goto not_this_one)
- sys/bus/pccard/pccard.c:496-501 (not_this_one; purge #if 0)
- sys/kern/subr_bus.c:2614-2644 (resource_list_add)
- sys/kern/subr_bus.c:2630-2631 (the panic)
- sys/bus/pccard/pccard_cis.c:1023-1098 (card-controlled iospace decoding)
Exploit chain
evil PC Card CIS (two CFTABLE_ENTRYs; first with one grantable + one ungrantable fixed io range, second with a grantable range) -> card insertion -> pccard_attach_card -> pccard_function_init partial allocation -> not_this_one without unwind -> next entry re-adds busy rid -> panic("resource_list_add: resource entry is busy") at insertion/boot. Deterministic local/physical DoS; no privilege boundary crossed (fixed panic site, no controllable data). Non-panicking variants (every entry failing mid-way) hold the granted bus windows until card removal.
Environment
Same guest/rig as DF-2318 (env.txt). Artifacts: run.log (baseline decisive), fixed_run.log (fix A/B), busypanic_pair.log (side-by-side), build.log, extract2_manifest.txt, matrix.log, seed_model/ (superseded hand model).
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
fixedVALIDATED. (1) Single-fix rig A/B (matrix.log, fixed_run.log): busypanic exits 0, cfe#1 allocates 0x200 cleanly, function attaches (devadded pnpinfo printed), io-windows-held=1, zero leak; all six other scenarios unchanged incl. negative controls. The originally-seeded fix.diff FAILED validation (resource_list_delete panic for uncleared res) and was corrected with trle->res = NULL before it passed. (2) Combined three-fix kernel: -Werror nativekernel rc=0, installkernel rc=0, booted kernel #1; rig re-extracted from the RUNNING kernel's patched source and re-driven: busypanic clean (postboot_run.log). In-kernel behavioral test impossible (no PCMCIA bridge).
fix.diff; fixed_run.log; busypanic_pair.log; matrix.log; postboot_extract_manifest.txt + postboot_run.log + kernel_apply.log + kernel_build.tail.log (in DF-2318 pack)
Confirmed kernel references
- sys/bus/pccard/pccard.c:425
- sys/bus/pccard/pccard.c:429
- sys/bus/pccard/pccard.c:439
- sys/bus/pccard/pccard.c:443
- sys/bus/pccard/pccard.c:449
- sys/bus/pccard/pccard.c:464
- sys/bus/pccard/pccard.c:483
- sys/bus/pccard/pccard.c:496
- sys/bus/pccard/pccard.c:499
- sys/kern/subr_bus.c:2614
- sys/kern/subr_bus.c:2619
- sys/kern/subr_bus.c:2630
- sys/kern/subr_bus.c:2631
- sys/bus/pccard/pccard_cis.c:1023
Detail
Exploit chain
evil PC Card CIS -> insertion -> pccard_attach_card -> pccard_function_init: cfe#0 partially allocates (first range granted + recorded busy, second range refused) -> not_this_one without unwind (#if 0 purge) -> cfe#1 grants its range -> resource_list_add(rl, SYS_RES_IOPORT, rid=0) finds the busy entry -> panic('resource entry is busy') at subr_bus.c:2631. Deterministic insertion/boot DoS; no privilege boundary crossed. Non-panicking variants (all entries failing mid-way) hold the granted bridge windows until removal.
Evidence (decisive lines)
run.log (decisive baseline: 'Allocation failed for cfe 0' then 'RIG KERNEL PANIC: resource_list_add: resource entry is busy', exit 42); fixed_run.log (fix A/B: exit 0, cfe#1 window granted, devadded fires, zero leak); busypanic_pair.log (side-by-side); matrix.log (f5355 flips exactly busypanic; controls green); extract2_manifest.txt (byte-identity); build.log; DF-2318 pack run.log/run.2.log/run.3.log (3/3 determinism); postboot_run.log in DF-2318 pack (combined-fix booted kernel)
PoC changes
Replaced the seeded hand-written model (preserved in seed_model/) with the verbatim rig: production pccard.c + subr_bus.c + pccard_cis.c code machine-extracted byte-identical and executed through pccard_attach_card. The seeded CIS encoding (little-endian fields, length+1 semantics) carried over unchanged and worked first try in the rig. The SEEDED fix.diff was buggy: its unwind called resource_list_delete without clearing rle->res and itself panicked ('resource_list_delete: resource has not been released', first matrix run); corrected fix adds trle->res = NULL (mirroring pccard_function_free at pccard.c:534) and now validates clean.
Verified recommended fix
Unwind partial allocations at not_this_one: for each busy rl entry, bus_release_resource + rle->res = NULL + resource_list_delete (restart scan after each mutation), removing both the busy-panic and the per-failed-entry window hold.
Verdict
REPRODUCED at the verbatim-rig level (3/3 deterministic), upgrading the seeded hand-model verification. The production pccard_function_init (pccard.c:407-503) and the production resource_list family (subr_bus.c:2594-2670) were machine-extracted BYTE-IDENTICAL from the guest's /usr/src (sha256 gates 5b610669.../949f75de...; PCCARD_BYTE_IDENTICAL=yes, SUBR_BUS_BYTE_IDENTICAL=yes) and driven through the real entry pccard_attach_card() with a crafted two-CFTABLE_ENTRY CIS: cfe#0 (anywhere range granted at rid 0 -> rle->res set, then fixed 0x3F8 refused by the bridge window) takes the not_this_one path whose purge is #if 0'd (pccard.c:499-501), leaving rid-0 busy; cfe#1's fixed 0x200 grant then re-enters resource_list_add for rid 0 and the verbatim panic fires: 'RIG KERNEL PANIC: resource_list_add: resource entry is busy' (subr_bus.c:2631), exit 42. In kernel context: deterministic panic at card insertion/boot. card.error stays 0 (the CIS parses cleanly), so the attach gate at pccard.c:205-212 does not help; every ingredient (entry count, per-entry ranges, sizes) is card-controlled. Kernel entry itself is hardware-gated (no PCMCIA bridge in QEMU, env.txt) -- DF-1040/1041/2319 precedent.
No comments yet.