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)
PoC verification
Evidence pack
findings/poc/DF-5446 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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_testableConfirmed 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.
No comments yet.