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

host_pcib_get_busno returns success without writing *busnum for Intel 82454NX at unexpected slot

Field Value
ID DF-1069
Status new
Severity Low
CVSS 3.1 CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L
CWE CWE-457 Use of Uninitialized Variable
File sys/bus/pci/pci_pci.c
Lines 707-726 (inner switch on slot), 752 (fall-through return 1)
Area bus/pci (PCI-PCI bridge / host-bridge bus-number detect)
Confidence likely
Discovered 2026-07-14
Reported pending
Known CVE none
CVE match dfly_specific

Summary

In host_pcib_get_busno, the inner switch on slot for device ID 0x84cb8086 (Intel 82454NX PXB) has no default case. If the device appears at a slot other than 0x12-0x15, *busnum is never written, yet the function falls through to return 1 (success). The sole caller, acpi_pcib_acpi_attach, declares uint8_t busno without initialization and unconditionally uses it on success β€” propagating an uninitialized kernel stack byte into sc->ap_bus, which becomes the PCI bus number for the host bridge.

Root cause

At pci_pci.c:707-726, case 0x84cb8086 contains an inner switch (slot) with cases 0x12, 0x13, 0x14, 0x15 only β€” no default:. When slot doesn't match (e.g. a malicious or mis-configured device spoofing ID 8086:84cb at slot 0x08), execution skips all inner cases, hits the outer break at line 726, exits the outer switch, and reaches return 1 at line 752 β€” signaling success without setting *busnum. Contrast with the outer switch which DOES have default: return 0 at line 747-749.

The caller at acpi_pcib_acpi.c:154 declares uint8_t busno; (uninitialized), and at line 230-234 does:

if (host_pcib_get_busno(..., &busno) == 0) {
    ...
} else {
    sc->ap_bus = busno;
    busok = 1;
}

so on the bogus return 1, the uninitialized busno is assigned to sc->ap_bus and busok is set to 1, causing pci_add_children to enumerate PCI bus at a garbage bus number.

Threat model & preconditions

  • Attacker position: Physical access (malicious FPGA PCIe card, evil PCIe device) or VM device-model control. The attacker presents a PCI device reporting vendor:device = 8086:84cb at a slot outside {0x12-0x15} on bus 0.
  • Privileges gained or impact: PCI mis-enumeration β€” the bus may be scanned at a wrong / non-existent bus number, causing devices to not be found (functional DoS) or potential bus-number collision with an existing bus (duplicate device probing, resource conflicts, possible boot-time panic). No memory corruption, no info leak to userspace (the uninitialized value stays in kernel).
  • Required config or capabilities: ACPI enabled (default on x86-64). Specific device-ID spoofing.
  • Reachability: Boot-time, hardware-triggered. Cannot be triggered from userspace.

Proof of concept

Boot-time, hardware-triggered. PoC approach:

  1. Using QEMU, create a custom PCI device (or patch an existing one's config-space device-ID register) to report PCIR_DEVVENDOR = 0x84cb8086 at a slot other than 0x12-0x15 on bus 0. A minimal QEMU setup: build a custom device model or use QEMU's PCI passthrough / assignment to present a device with the crafted ID.
  2. Boot DragonFlyBSD with ACPI enabled.
  3. During acpi_pcib_acpi_attach for the host bridge at that device, host_pcib_get_busno is called; it reads the forged 0x84cb8086, enters case 0x84cb8086, the inner switch finds no matching slot, returns 1 without setting *busnum.
  4. Observe in dmesg: the host bridge is assigned a garbage bus number; PCI enumeration of that bus finds wrong / no devices, or a duplicate-bus panic occurs.

Build & run

# Requires a custom QEMU device model or PCI passthrough config that presents
# vendor:device 8086:84cb at a non-{0x12-0x15} slot on bus 0.
qemu-system-x86_64 -enable-kvm -m 512 -hda dfbsd.img
# Watch dmesg for "pcib0: <ACPI Host-PCIB>" followed by mis-enumeration or panic.

Expected output

System mis-enumerates PCI (devices on the host bridge not found) or fails to boot due to bus-number collision. No userspace trigger; this is purely a boot-time / firmware-control bug.

Impact

Functional PCI mis-enumeration when a malicious PCIe device spoofs the Intel 82454NX device ID at an unexpected slot. No memory corruption. No info leak to userspace. Limited to availability (PCI devices may be missed at boot). Low severity.

Add a default case to the inner switch that returns failure (0), since the bus number cannot be determined for an unknown slot. This matches the outer switch's behavior for unknown device IDs.

--- a/sys/bus/pci/pci_pci.c
+++ b/sys/bus/pci/pci_pci.c
@@ -722,6 +722,8 @@ host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func,
        case 0x15:
            /* Intel 82454NX PXB#1, Bus#B */
            *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1;
            break;
+       default:
+           /* Unknown slot for this chipset; cannot determine bus number. */
+           return (0);
        }
        break;

This ensures that for any unexpected slot, the function signals failure (return 0), and the caller falls through to its fallback bus-number logic (unit-number heuristic at acpi_pcib_acpi.c:244+) instead of using an uninitialized value.

References

Timeline

  • 2026-07-14 Discovered during automated audit.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1069 Β· 3 files
FileTypeDescriptionSize
fix.diff suggested-fix git-apply-able fix for the cited path 320 B view raw
VERDICT.md verdict source-confirmation narrative 945 B ↓ raw
env.txt environment guest uname + toolchain 247 B view raw
VERDICT.md verdict source-confirmation narrative
↓ download raw

DF-1069 source-confirmation

Verdict: REPRODUCED (source-confirmed) Impact: none Confidence: speculative

Kernel ref: sys/bus/pci/pci_pci.c:708

Mechanism

host_pcib_get_busno missing inner default: Intel 82454NX inner switch(slot) has no default; unexpected slot returns success without writing *busnum -> uninit bus number. malicious PCIe device; confirmed.

Confirmation method

source-only Low-severity; confirmation by code inspection. Runtime PoC not exercised for this Low-severity item; confirmation is by code inspection against sys/.

See fix.diff in this folder (git-apply-able unified diff).

Phase 8 (combined build)

This fix is part of the batched 70-finding combined patch (../_batch70/combined_70.patch) applied to in-guest /usr/src. A single make -j6 nativekernel KERNCONF=X86_64_GENERIC build is validated rc=0 with 0 errors under -Werror (../_batch70/fix_build.log).

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

VALIDATED via combined build: fix in combined_70.patch; single make -j6 nativekernel built rc=0, 0 errors under -Werror (../_batch70/fix_build.log). Cited line corrected. Source-only -> validation = clean -Werror compile.

'>>> Kernel build for X86_64_GENERIC completed' + 'NK_DONE rc=0'; grep -cE 'error:|undefined reference' fix_build.log = 0
↓ fix.diffDragonFly 6.5-DEVELOPMENT combined 70-finding fix kernel (built rc=0 -Werror 2026-07-23; not booted - source-only)

Confirmed kernel references

Detail

Exploit chain

none (source-only Low finding, not memory-corruption driven to runtime; no escalation chain)

Evidence (decisive lines)

baseline (with-src #0): bug at sys/bus/pci/pci_pci.c:708. combined-70 fix kernel: NK_DONE rc=0 (0 errors, -Werror).

PoC changes

authored/validated fix.diff (findings/poc/DF-1069/fix.diff); part of combined_70 kernel build.

Verified recommended fix

See findings/poc/DF-1069/fix.diff (git-apply-able). Matches finding proposal.

Verdict

REAL: host_pcib_get_busno Intel 82454NX inner switch has no default -> unexpected slot returns success without *busnum -> uninit bus number. malicious PCIe. confirmed.