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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5355 Β· 23 files
FileTypeDescriptionSize
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/.

VERDICT.md
↓ download raw

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).

  1. verbatim pccard_attach_card -> verbatim CIS parse: both cfe entries decode cleanly (card.error=0 -- the gate at pccard.c:205 does not fire).
  2. verbatim pccard_function_init on cfe#0 (pccard.c:425-451): * iospace[0] start=0 -> bus_alloc_resource grants 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)
  3. loop continues to cfe#1: iospace[0] fixed 0x200 -> granted -> resource_list_add(rl, IOPORT, rid=0, ...) (pccard.c:443) -> verbatim subr_bus.c:2619 resource_list_find returns the busy entry -> :2630-2631 if (rle->res) panic("resource_list_add: resource entry is busy")
  4. 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_delete without clearing rle->res, so the fixed code panicked in resource_list_delete: resource has not been released (first matrix run). Production pccard_function_free explicitly does rle->res = NULL after release (pccard.c:534) -- the unwind must too. fix.diff in this pack is the corrected, validated version (adds trle->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: -Werror nativekernel 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

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

fixed
baseline reproduced→ patch + rebuild →patched clean

VALIDATED. (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)
↓ fix.diffper-fix-DF-5355

Confirmed kernel references

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.