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_GTPMAPioctl. A malicious or buggy FireWire device is needed to inflatecrc_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_lenhas been inflated, the user'sFW_GTPMAPbuffer receives kernel heap bytes that were never part of the topology map. 2. Kernel panic (A:H) β ifcrc_lenis so large that thebcopywalks into an unmapped kernel page, the kernel page-faults. - Required config or capabilities: Default kernel with
firewireconfigured. Local operator-group membership. A malicious FireWire device on the bus (or a related bug that growscrc_len) is needed to inflate the count. - Reachability:
open("/dev/fwN", O_RDWR); ioctl(fd, FW_GTPMAP, &buf);oncecrc_lenhas 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".
Recommended fix
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
sys/bus/firewire/fwdev.c:657-660βFW_GTPMAPbcopy with unbounded countsys/bus/firewire/firewire.c:738βtopology_mapallocation (sizeof(struct fw_topology_map))sys/bus/firewire/firewire.c:1124, 1142-1143βcrc_lenincrement infw_sidrcvsys/bus/firewire/firewire.h:361-368βstruct fw_topology_map(room for 256 self_ids)- CWE-125 Out-of-bounds Read
- CWE-129 Improper Validation of Array Index
Timeline
- 2026-07-14 Discovered during automated audit.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1060 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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 |
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
fwohciattachment, 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.
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_mapis allocated as exactlysizeof(struct fw_topology_map)β 1036 bytes (sys/bus/firewire/firewire.c:738).crc_lenisuint16_t, so the count can be up to(65535+1)*4 = 262144bytes.crc_lenis incremented once per received self-id packet infw_sidrcvatfirewire.c:1143without any bound against thetopology_mapallocation. The relatedsid_cnt = len/8atfirewire.c:1124is also unvalidated.- Once
crc_len > ~258, thebcopyreads past thetopology_mapallocation and writes those kernel heap bytes into the user buffer. With a very largecrc_lenthebcopymay 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
sys/bus/firewire/fwdev.c:657-660βFW_GTPMAPbcopy with unbounded countsys/bus/firewire/firewire.c:738βtopology_mapallocation sizesys/bus/firewire/firewire.c:1124, 1142-1143βcrc_lenincrement infw_sidrcv(unbounded)sys/bus/firewire/firewire.hβstruct fw_topology_map(room for 256 self_ids)
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_testablecompile+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.
No comments yet.