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

Unchecked 4-byte logical-ID read on short PNP_TAG_LOGICAL_DEVICE descriptor (≀3-byte overread; worst case past the allocation into uninitialized heap)

Summary

bcopy(resinfo,&logical_id,4) executes although only the declared 0..7 bytes were validated: a declared length <4 reads up to 3 bytes past the descriptor, and len==space is arrangeable so the tail tag reads past the kmalloc allocation - taints logical_id (quirk matching, probe strings). Same shape at pnpparse.c:95. Static only (Low). Length>=4-reject fix at both sites.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5446 Β· 3 files
FileTypeDescriptionSize
README.md β€” 1.3 KB ↓ raw
verdict.json β€” 2.7 KB view raw
manifest.json β€” 664 B view raw

DF-5446 β€” unchecked 4-byte logical-ID read on short PNP_TAG_LOGICAL_DEVICE (sys/bus/isa/pnp.c:444)

What (static analysis; not guest-verified β€” Low)

pnp_create_devices() handles PNP_TAG_LOGICAL_DEVICE with an unconditional

bcopy(resinfo, &logical_id, 4);          /* pnp.c:444 */

The bounds check only validated PNP_SRES_LEN(tag) bytes (pnp.c:419-425) β€” the small-tag length field is card-controlled (0..7). With a declared length < 4 the bcopy reads up to 3 bytes past the descriptor's declared data; when the tag sits at the tail of the resource buffer and the buffer was grown to exactly len == space, the read runs past the kmalloc allocation into uninitialized kernel heap. The tainted logical_id feeds isa_set_logicalid() (pnp.c:452), quirk matching (pnp.c:445) and is rendered by pnp_eisaformat() in probe messages β€” a weak kernel-heap info leak to the console/log.

Same family as the pnpparse.c PNP_TAG_COMPAT_DEVICE bcopy (pnpparse.c:95).

Fix direction

Validate the length before the copy:

if (PNP_SRES_LEN(tag) < 4) { device_printf(parent, "short logical-device tag\n"); scanning = 0; break; }

Status

untested β€” Low severity, boot-time hardware trigger; not PoC'd on the guest (no fix.diff; see verdict.json).

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean
per-fix-DF-5446

Confirmed kernel references

Detail

Evidence (decisive lines)

Static: pnp.c:419-425 (declared-length-only validation), pnp.c:444 (unchecked 4-byte read), pnp.c:445-452 (quirk match, logical-id ivar), pnp.c:398-413 (unrelated ANSI path shows how lengths are handled elsewhere); pnp_read_bytes growth semantics pnp.c:506-515 (len can equal space exactly); pnpparse.c:95 (same pattern).

Verified recommended fix

In pnp_create_devices() PNP_TAG_LOGICAL_DEVICE, require PNP_SRES_LEN(tag) >= 4 before the bcopy (else device_printf + scanning=0); mirror for PNP_TAG_COMPAT_DEVICE in pnpparse.c:95.

Verdict

NOT guest-verified (Low severity, boot-time hardware trigger; below the PoC bar for this run). Static analysis is solid: pnp_create_devices() handles PNP_TAG_LOGICAL_DEVICE with an unconditional 4-byte bcopy(resinfo, &logical_id, 4) at sys/bus/isa/pnp.c:444, but the only bounds validation performed is for the tag's declared length PNP_SRES_LEN(tag) in pnp.c:419-425 β€” a card-controlled 0..7 value. A declared length of 0..3 leaves the bcopy reading 1-3 bytes past the descriptor's data; when the tag sits at the tail of the resource buffer and the buffer occupies len == space of the kmalloc'd region (attacker-arrangeable: pnp_read_bytes guarantees only len+amount <= space), the read crosses the allocation into uninitialized kernel heap. The tainted logical_id is stored via isa_set_logicalid() (pnp.c:452), matched against pnp_quirks (pnp.c:445) and rendered to the console/log through pnp_eisaformat()-based probe output β€” a weak kernel-heap info-leak channel (1-3 bytes per malformed tag). The sibling parser pnpparse.c:95 has the identical unchecked bcopy for PNP_TAG_COMPAT_DEVICE. Recommended fix: reject the tag when PNP_SRES_LEN(tag) < 4 (device_printf + stop scanning), as written in README.md.