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

adv_pci_attach leaves the active IRQ resource allocated when bus_setup_intr() fails after bus_alloc_resource(SYS_RES_IRQ) succeeded

Summary

The setup_intr-failure unwind releases only the IOPORT - the RF_ACTIVE IRQ stays pinned forever (failed attach means no detach). adv twin of DF-4969 (adw_pci). Replay harness mode 2: IRQ=0 releases - leak proven; patched clean.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5043 Β· 5 files
FileTypeDescriptionSize
run.log run-log both modes; mode-2 section shows IRQ=0 releases + LEAK PROVEN marker 2.4 KB view raw
run.2.log run-log patched replay: IRQ=1 released, unwind clean 2.2 KB view raw
fix.diff suggested-fix same diff as DF-5042 (IRQ-release hunk is this finding's fix) 1.1 KB view raw
VERDICT.md verdict full narrative 2.9 KB ↓ raw
../DF-5042/ harness shared verbatim-replay kld (wrapper.c/advansys_shim.c/fkdecl.h/Makefile/build.sh) 4.0 KB ↓ download
VERDICT.md verdict full narrative
↓ download raw

DF-5043 β€” VERDICT

Verdict: REPRODUCED (runtime replay of verbatim driver code; HW-gated natural trigger) Class: resource leak (CWE-772) Impact ceiling: none (pinned IRQ resource per failed attach) Confidence: certain

Reproduction

Same harness as DF-5042 (see ../DF-5042/VERDICT.md for the technique). Mode 2 (kenv df5042.irqfail=1): the verbatim adv_pci_attach() reaches the interrupt stage; fk_bus_alloc_resource hands out a fake IRQ resource and records it; fk_bus_setup_intr returns failure; the adv_pci.c:289-294 unwind calls adv_free() and bus_release_resource(dev, SYS_RES_IOPORT, ...) only. Observed in run.log:

FK: bus_alloc_resource(IRQ) -> fake irq resource 0xffffffff82606820
FK: bus_setup_intr -> scripted FAILURE
FK: bus_release_resource(IOPORT)
DF5042: bus_release_resource: IOPORT=1 IRQ=0; bus_setup_intr calls=1
DF5042: *** IRQ resource NEVER RELEASED on the bus_setup_intr failure unwind -- DF-5043 LEAK PROVEN ***

Mechanism (source-confirmed)

adv_pci.c:287-294:

irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &irqrid, 0, ~0, 1,
                RF_SHAREABLE | RF_ACTIVE);
if (irqres == NULL ||
    bus_setup_intr(dev, irqres, 0, adv_intr, adv, &ih, NULL)) {
    adv_free(adv);
    bus_release_resource(dev, SYS_RES_IOPORT, rid, iores);   /* only IOPORT */
    return ENXIO;
}

When bus_alloc_resource succeeded but bus_setup_intr failed, irqres is never released (SYS_RES_IRQ, rid 0, RF_ACTIVE). Because the attach fails, newbus (device_doattach, sys/kern/subr_bus.c:2115-2124) unbinds the driver without invoking any detach method β€” nothing ever releases the resource. The device is left in DS_NOTPRESENT with an active rman IRQ reservation against it; re-probes of the device continue to work only because rman re-grants the same owner, but the reservation (and its interrupt vector bookkeeping for MSI systems) persists. This is the adv twin of DF-4969 (adw_pci error unwinds).

Fix validation (runtime A/B)

The IRQ-release hunk of fix.diff (identical file as DF-5042's pack; the diff covers both unwind defects) adds:

if (irqres != NULL)
    bus_release_resource(dev, SYS_RES_IRQ, irqrid, irqres);

Patched replay (run.2.log): bus_release_resource: IOPORT=1 IRQ=1, "unwind clean (fix effective?)". Baseline vs patched on the same guest, same scripted chip, same verbatim driver code.

Gating precondition

AdvanSys 0x10CD PCI HBA whose attach passes DMA/chip init but fails bus_setup_intr (IRQ exhaustion, msix setup failure), or a VFIO endpoint engineered to do so. Availability hygiene only; no escalation path.

Exploit chain

Not applicable.

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

Baseline: IRQ resource released 0 times (marker printed). Patched (fix.diff applied to the adv_pci.c copy the kld compiles): 'bus_release_resource: IOPORT=1 IRQ=1', 'unwind clean (fix effective?)'. Runtime A/B on the same guest/kernel, no hardware.

run.log (baseline mode 2: IRQ=0 + LEAK PROVEN); run.2.log (patched: IRQ=1, unwind clean); fix_build.log
↓ fix.diffper-fix-DF-5043

Confirmed kernel references

Detail

Evidence (decisive lines)

run.log mode-2 section ('FK: bus_alloc_resource(IRQ) -> fake irq resource', 'FK: bus_setup_intr -> scripted FAILURE', 'DF5042: bus_release_resource: IOPORT=1 IRQ=0', '*** IRQ resource NEVER RELEASED ... DF-5043 LEAK PROVEN ***'); run.2.log patched ('IOPORT=1 IRQ=1', 'unwind clean'); fix.diff; VERDICT.md

PoC changes

Uses the DF-5042 harness unchanged; this finding is mode 2 (kenv df5042.irqfail=1) of the same kld.

Verified recommended fix

In the bus_setup_intr failure unwind, release the IRQ resource when it was allocated: if (irqres != NULL) bus_release_resource(dev, SYS_RES_IRQ, irqrid, irqres); (see the second hunk of fix.diff)

Verdict

When bus_alloc_resource(SYS_RES_IRQ) succeeds but bus_setup_intr() fails, the adv_pci.c:289-294 unwind calls adv_free() and releases only the IOPORT resource - the active IRQ resource is never bus_release_resource'd, and since the attach fails, newbus (device_doattach, subr_bus.c:2115-2124) unbinds the driver without running any detach, so nothing ever releases it. Reproduced at runtime on the guest with the DF-5042 verbatim-replay harness in mode 2 (kenv df5042.irqfail=1): 'bus_release_resource: IOPORT=1 IRQ=0' and the harness's ' IRQ resource NEVER RELEASED ... DF-5043 LEAK PROVEN ' marker. Natural trigger HW-gated (AdvanSys 0x10CD HBA; none on guest). Impact is a pinned rman IRQ reservation per failed attach - availability hygiene, no corruption/disclosure. The IRQ-release hunk of fix.diff validated by runtime A/B: patched replay shows 'IOPORT=1 IRQ=1', 'unwind clean'. adv twin of DF-4969 (adw_pci).