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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2292 Β· 6 files
FileTypeDescriptionSize
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
VERDICT.md verdict gate analysis + FW_ASYREQ overflow trace
↓ download 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.

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_testable
baseline no→ patch + rebuild →patched clean

not_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).
↓ fix.diffn/a (no target HW/device on this guest)

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.