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

FW_GTPMAP bcopy uses (topology_map->crc_len + 1) * 4 as the count β€” attacker-inflatable crc_len drives unbounded kernel OOB read up to 256 KB

Field Value
ID DF-1060
Status new
Severity Medium
CVSS 3.1 CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:H
CWE CWE-125 Out-of-bounds Read; CWE-129 Improper Validation of Array Index
File sys/bus/firewire/fwdev.c
Lines 657-660 (FW_GTPMAP bcopy)
Area bus/firewire (FireWire /dev/fwN topology-map ioctl)
Confidence likely
Discovered 2026-07-14
Reported pending
Known CVE none
CVE match dfly_specific

Summary

The FW_GTPMAP handler at fwdev.c:657-660 copies (sc->fc->topology_map->crc_len + 1) * 4 bytes out of sc->fc->topology_map to the user buffer. crc_len is a 16-bit field, so the count can be up to (65535+1)*4 = 262144 bytes, while topology_map is allocated as exactly sizeof(struct fw_topology_map) β‰ˆ 1036 bytes (firewire.c:738). The kernel increments crc_len once per received self-id packet in fw_sidrcv (firewire.c:1143) without ever bounding it against the topology_map allocation. A malicious FireWire device (or a hardware/protocol bug that inflates sid_cnt) can drive crc_len well past the buffer size; the FW_GTPMAP ioctl then reads adjacent kernel heap into user memory.

Root cause

/* fwdev.c:657-660 β€” the bug */
case FW_GTPMAP:
    bcopy(sc->fc->topology_map, ap->a_data,
        (sc->fc->topology_map->crc_len + 1) * 4);
    break;

fwdev.c:658-659 unconditionally trusts topology_map->crc_len. topology_map is struct fw_topology_map (firewire.h:361-368) which has room for self_id[4*64] (256 entries). The kernel bumps crc_len for each valid self-id packet at firewire.c:1143 with no upper-bound check, and sid_cnt = len/8 at firewire.c:1124 is also unvalidated against the buffer. Once crc_len exceeds ~258, FW_GTPMAP reads past the topology_map allocation (kernel OOB read) and writes those leaked kernel heap bytes into the user's buffer.

Threat model & preconditions

  • Attacker position: Local operator-group user for the FW_GTPMAP ioctl. A malicious or buggy FireWire device is needed to inflate crc_len (the user-side call only leaks the bytes the device already caused to be over-counted).
  • Privileges gained or impact: 1. Kernel info leak (C:H) β€” when crc_len has been inflated, the user's FW_GTPMAP buffer receives kernel heap bytes that were never part of the topology map. 2. Kernel panic (A:H) β€” if crc_len is so large that the bcopy walks into an unmapped kernel page, the kernel page-faults.
  • Required config or capabilities: Default kernel with firewire configured. Local operator-group membership. A malicious FireWire device on the bus (or a related bug that grows crc_len) is needed to inflate the count.
  • Reachability: open("/dev/fwN", O_RDWR); ioctl(fd, FW_GTPMAP, &buf); once crc_len has been inflated by a malicious device.

Proof of concept

Triggering from the local side requires crc_len to already be inflated. Without a malicious device this is normally small (≀ ~258). The audit PoC therefore targets the user-side call to demonstrate the OOB read once crc_len is large; to fully exercise it you need either a software FireWire controller, an ICOM-style sbp tool that injects self-ids, or a second cooperating bug that grows crc_len:

/* df-fw-gtpmap-oob.c */
#include <fcntl.h>
#include <sys/ioctl.h>
#include <bus/firewire/firewire.h>
#include <stdio.h>

int main(void) {
    int fd = open("/dev/fw0", O_RDWR);
    if (fd < 0) { perror("open"); return 1; }
    /* Allocate generously so the bcopy can write a large payload back. */
    static unsigned char buf[65536 * 4];
    if (ioctl(fd, FW_GTPMAP, buf) < 0) { perror("FW_GTPMAP"); return 1; }
    /* On a benign system this returns ≀ sizeof(struct fw_topology_map) β‰ˆ 1036 bytes.
     * If crc_len has been inflated, you receive kernel heap bytes beyond the
     * topology_map allocation. */
    unsigned int *p = (unsigned int *)buf;
    printf("crc_len field  = %u\n", p[0] >> 16);
    printf("bytes returned beyond topology_map allocation are kernel-heap leak.\n");
    return 0;
}

Build & run

cc -o df-fw-gtpmap-oob df-fw-gtpmap-oob.c   # may need -I/usr/src
./df-fw-gtpmap-oob

Expected output

On a system where crc_len has been inflated (by a malicious device or by trigger of the related *self_id = ... OOB write at firewire.c:1142 which writes past self_id[256]), the output shows non-zero bytes past offset ~1036 of buf, demonstrating kernel heap disclosure.

Impact

Local kernel heap disclosure of up to 256 KB per FW_GTPMAP call when crc_len has been inflated by a malicious FireWire device. Scope:Changed reflects the cross-domain leak (host kernel heap β†’ FireWire bus). High complexity (requires device-side setup). Medium severity per "info leak of limited kernel memory".

Cap the copy at the allocation size. The structure's max valid crc_len is 3 + 256 (header + max self_id entries); hard cap to sizeof(struct fw_topology_map)/4 - 1.

--- a/sys/bus/firewire/fwdev.c
+++ b/sys/bus/firewire/fwdev.c
@@ -657,7 +657,10 @@
        break;
    case FW_GTPMAP:
-       bcopy(sc->fc->topology_map, ap->a_data,
-           (sc->fc->topology_map->crc_len + 1) * 4);
+       {
+           u_int cl = sc->fc->topology_map->crc_len;
+           if (cl > sizeof(struct fw_topology_map)/4 - 1)
+               cl = sizeof(struct fw_topology_map)/4 - 1;
+           bcopy(sc->fc->topology_map, ap->a_data, (cl + 1) * 4);
+       }
        break;

Also fix fw_sidrcv (firewire.c:1136-1183) to bound the self-id loop at 4*64 entries and stop incrementing crc_len past that.

References

Timeline

  • 2026-07-14 Discovered during automated audit.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1060 Β· 8 files
FileTypeDescriptionSize
fw_gtpmap_oob_read.c trigger-source doc-only PoC (no /dev/fw*) 1.2 KB view raw
build.sh build-script no-op (doc-only) 174 B view raw
run.sh run-script no-op (doc-only) 334 B view raw
fix.diff suggested-fix cap crc_len at sizeof(struct fw_topology_map)/4 - 1 581 B view raw
fix_build_full.log build-log combined 5-patch kernel build (rc=0) 5.6 MB ↓ download
env.txt environment guest uname, securelevel, cc version 560 B view raw
VERDICT.md verdict detailed analysis 3.3 KB ↓ raw
README.md readme human-readable summary 1.1 KB ↓ raw
README.md readme human-readable summary
↓ download raw

DF-1060 β€” FW_GTPMAP bcopy with attacker-inflatable crc_len (OOB read)

Summary

FW_GTPMAP at sys/bus/firewire/fwdev.c:657-660 copies (sc->fc->topology_map->crc_len + 1) * 4 bytes from topology_map to the user buffer. crc_len is uint16 and is incremented once per self-id packet in fw_sidrcv (firewire.c:1143) without bound; the topology_map allocation is only ~1036 bytes. With crc_len inflated, the bcopy leaks up to 256 KB of adjacent kernel heap into user memory.

HW / preconditions

  • FireWire PCI host controller (no fwohci attachment, no /dev/fw* on this QEMU guest).
  • AND a malicious/buggy FireWire device that floods self-id packets to inflate crc_len.

Doubly-unreachable on this guest β€” code-confirmed only.

Build / Run

No buildable PoC (no /dev/fw*). ./build.sh && ./run.sh print the situation. The bug is documented in fw_gtpmap_oob_read.c.

Fix

fix.diff caps crc_len at sizeof(struct fw_topology_map)/4 - 1 so the bcopy can never read past the allocation. A full fix would also bound the self-id loop in fw_sidrcv; that is out of scope here.

VERDICT.md verdict detailed analysis
↓ download raw

DF-1060 β€” FW_GTPMAP bcopy with attacker-inflatable crc_len (OOB read)

Verdict

NOT REPRODUCED β€” code-confirmed latent bug; cannot trigger on this guest (no FireWire PCI controller, /dev/fw* absent). Also: the OOB read requires crc_len to have already been inflated by a malicious FireWire device, which is itself an out-of-guest precondition.

Mechanism (source-confirmed)

In sys/bus/firewire/fwdev.c:fw_ioctl:

case FW_GTPMAP:
    bcopy(sc->fc->topology_map, ap->a_data,
            (sc->fc->topology_map->crc_len + 1) * 4);
    break;
  • topology_map is allocated as exactly sizeof(struct fw_topology_map) β‰ˆ 1036 bytes (sys/bus/firewire/firewire.c:738).
  • crc_len is uint16_t, so the count can be up to (65535+1)*4 = 262144 bytes.
  • crc_len is incremented once per received self-id packet in fw_sidrcv at firewire.c:1143 without any bound against the topology_map allocation. The related sid_cnt = len/8 at firewire.c:1124 is also unvalidated.
  • Once crc_len > ~258, the bcopy reads past the topology_map allocation and writes those kernel heap bytes into the user buffer. With a very large crc_len the bcopy may walk into an unmapped kernel page β†’ panic.

The user-side FW_GTPMAP call therefore (a) leaks kernel heap bytes when crc_len has been inflated, and (b) can panic the kernel.

Why not reproduced on this guest

Two stacked absent preconditions: 1. The QEMU audit guest has no FireWire PCI host controller, so no firewire0 instance, no /dev/fw* device node, and no way to issue FW_GTPMAP. (kldstat -v shows the fwohci/firewire driver present in the kernel, but inert.) 2. Even on a FW-equipped host, the leak requires crc_len to already be inflated β€” either by a malicious/buggy FireWire device flooding self-id packets, or by trigger of the related self_id[256] OOB write at firewire.c:1142. Without that, a benign system has crc_len ≀ ~258 and the bcopy stays in-bounds.

Per Phase-4(c)/(d): real bug, doubly-unreachable on this guest. Source-only confirmation; the bug is latent.

Fix

fix.diff caps crc_len at sizeof(struct fw_topology_map)/4 - 1 (the maximum that fits in the allocation):

case FW_GTPMAP:
    {
        u_int cl = sc->fc->topology_map->crc_len;
        u_int maxcl = sizeof(struct fw_topology_map) / 4 - 1;
        if (cl > maxcl)
            cl = maxcl;
        bcopy(sc->fc->topology_map, ap->a_data, (cl + 1) * 4);
    }
    break;

A complete fix would ALSO bound the self-id loop in fw_sidrcv (firewire.c:1136-1183) at 4*64 entries and stop incrementing crc_len past that β€” that is a separate code change recommended in the finding markdown but out of scope for the user-side FW_GTPMAP OOB read. Validated as part of a combined 5-patch kernel build that compiled cleanly and booted.

Kernel references

PoC changes

fw_gtpmap_oob_read.c is doc-only. fix.diff is git-apply-able and verified to apply + compile as part of a combined patched-kernel build.

Fix verification

not_testable

compile+boot validated

see evidence pack

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. FW_GTPMAP bcopy (crc_len+1)*4 unbounded -> OOB read. No FW HW.