FW_ASYREQ response copy overflows ioctl heap buffer with oversized FireWire RRESB payload
Summary
When copying async-response packet back into user fw_asyreq ioctl buffer kernel uses user-supplied req.len as proxy for destination-buffer capacity instead of actual fixed-size data[512] array (2048 bytes). A FireWire peer responding to RREQB with RRESB payload exceeding 2048 bytes causes bcopy up to 4080 bytes of attacker-controlled response data into 2048-byte data[] region overflowing mapped_ioctl heap buffer by up to ~2032 bytes. Guard at :578 only checks req.len large enough to describe response. recv.payload allocated PAGE_SIZE=4096. No maxrec/MAXREC check on receive path. Attacker controls FireWire node on bus plus local operator-group access. Impact: kernel heap corruption with controlled data -> heap grooming -> local privilege escalation.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2292 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | gate analysis + FW_ASYREQ overflow trace | 3.4 KB | β raw |
| fix.diff | suggested-fix | bound response copy to sizeof(asyreq->data) not user req.len | 566 B | view raw |
| build.sh | build-script | documents HW gate | 145 B | view raw |
| run.sh | run-script | prints gate proof | 257 B | view raw |
| env.txt | environment | guest env | 1.1 KB | view raw |
| gate_proof.txt | gate-proof | no fwohci, no /dev/fw* | 61 B | view raw |
DF-2292 β FW_ASYREQ response copy overflows ioctl heap buffer (fwdev.c)
Verdict: NOT REPRODUCED (HW-gated); REAL BUG IN SOURCE (defense-in-depth fix warranted)
Hardware gate (why the PoC cannot run on this guest)
FW_ASYREQ is an ioctl on /dev/fw<N> (a per-FireWire-node device created when
a remote 1394 node is enumerated by an attached fwohci controller). The audit
guest has no FireWire controller and no /dev/fw* devices:
$ pciconf -l | grep -iE "fwohci|firewire" # (no output) $ ls /dev/fw* # /dev/fw*: No such file or directory
With no controller attached there is no FireWire bus, no enumerated nodes, no
/dev/fw<N>, and no peer that could answer an async-stream request with an
oversized RRESB response. The unprivileged maxx user cannot open a
non-existent device node. The hw.firewire.* sysctl defaults exist only because
the subsystem is compiled in.
Source trace β the bug is REAL (sys/bus/firewire/fwdev.c)
The struct fw_asyreq ioctl argument (firewire.h:251-266) is:
struct fw_asyreq {
struct fw_asyreq_t { unsigned char sped; unsigned int type;
unsigned short len; union { struct fw_eui64 eui; } dst; } req;
struct fw_pkt pkt;
u_int32_t data[512]; /* fixed 2048-byte user buffer */
};
In fw_ioctl/FW_ASYREQ (fwdev.c:538-587), after sending the async request
and tsleep-ing for the response, the kernel copies the peer's response back
into the caller's fw_asyreq:
/* copy response */
tinfo = &sc->fc->tcode[xfer->recv.hdr.mode.hdr.tcode];
if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) /* fwdev.c:578 */
asyreq->req.len = xfer->recv.pay_len; /* fwdev.c:579 */
else
err = EINVAL;
bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len); /* fwdev.c:582 */
bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len,
MAX(0, asyreq->req.len - tinfo->hdr_len)); /* fwdev.c:583 */
The check at line 578 uses the user-supplied asyreq->req.len as a proxy
for the destination buffer's capacity. But the real capacity is the fixed
data[512] array (2048 bytes) beginning at &asyreq->pkt. Line 579 then sets
asyreq->req.len = xfer->recv.pay_len β the length of the peer's response
payload, which the kernel does not bound against the buffer. recv.payload is
allocated PAGE_SIZE (4096), so a malicious FireWire peer answering an RREQB
with an RRESB payload up to ~4080 bytes causes line 583's bcopy to write up to
~4080 bytes of attacker-controlled data into the 2048-byte data[] region β a
~2032-byte heap overflow of the mapped_ioctl-supplied buffer.
There is no MAXREC / maxrec clamp on the receive path. Impact (on hardware):
kernel heap corruption with controlled bytes from a FireWire peer; the operator
group can open /dev/fw<N> on DragonFly, so this is an unprivileged-user +
malicious-peer vector on firewire-equipped hosts.
Exploit chain status
Not pursuable β primitive is behind absent FireWire hardware (valid Phase-6 hard blocker). On real hardware this is a write-capable heap-corruption primitive.
PoC changes
None. /dev/fw* absent; verified by source trace only.
Recommended fix
Clamp the response copy to the actual destination capacity (the fixed data[]
array). See fix.diff (supersedes finding proposal: bounds-checks the bcopy
length against sizeof(asyreq->data) instead of trusting user req.len).
Fix verification
not_testablenot_testable: PoC cannot run on this guest (HW-gated, no target device). fix.diff validated by git apply --check (clean) + line-accurate source trace confirming it closes the cited path.
git apply --check findings/poc/DF-2292/fix.diff -> OK (clean apply). No runtime test possible (HW-gated).
Confirmed kernel references
Detail
Exploit chain
none β valid hard blocker (driver/device path dead at runtime on this guest: no target HW / no attached device). No unprivileged->root path.
Evidence (decisive lines)
usbconfig list -> No device match or lack of permissions.; pciconf -l -> no target controller HW; ifconfig -l -> vtnet0 lo0; kldstat -> kernel/ehci/xhci only; ls /dev/<target> -> No such file or directory; id maxx -> uid=1001 groups=1001 (not operator). Source confirmed at cited lines.
PoC changes
Created findings/poc/DF-2292/{VERDICT.md,fix.diff,build.sh,run.sh,env.txt,gate_proof.txt,manifest.json}. No PoC source (HW-gated).
Verified recommended fix
reject pay_len > sizeof(asyreq->data) before bcopy. Full git-apply-able diff in findings/poc/DF-2292/fix.diff (git apply --check OK).
Verdict
NOT REPRODUCED (HW-gated). The bug is REAL in source (traced line-by-line). fwdev FW_ASYREQ response copy overflows ioctl heap (data[512], peer pay_len unbounded); no /dev/fw. Gate confirmed via usbconfig list (No device match / no /dev/ugen), pciconf -l (no target controller HW), ifconfig (vtnet0 lo0 only), kldstat (no target module), and ls /dev (no target nodes). maxx (uid 1001, not in operator) cannot reach any /dev/usbctl write path.
No comments yet.