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

Unbounded ksprintf into fixed 8-byte schan.hookname in musycc_newhook

  • File: sys/dev/misc/musycc/musycc.c
  • Lines: 167, 1072, 1077, 1086, 1268, 1294
  • Severity: Low
  • CVSS: CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:N
  • CWE: CWE-787 Out-of-bounds Write
  • Confidence: likely

Summary

musycc_newhook does ksprintf(sch->hookname, name) with no size limit (the source even carries an XXX overflow ? comment) into the fixed 8-byte schan.hookname[] member.

Because netgraph hook names are capped at NG_HOOKSIZ-1=31 chars at the message layer, up to 32 bytes are written, overrunning hookname by up to 24 bytes into the subsequent hook/rx_drop/tx_limit fields.

Most of the overwritten fields are subsequently re-initialised (hook at line 1085, tx_limit at 1086, nmd/rx_last_md/tx_*_md inside musycc_connect at 1268–1294) which substantially contains the impact, but schan.rx_drop is never reset and is left holding attacker-controlled ASCII bytes for the channel's lifetime.

Root cause

At sys/dev/misc/musycc/musycc.c:1077 inside musycc_newhook the code calls ksprintf(sch->hookname, name); /* XXX overflow ? */.

struct schan.hookname is declared char hookname[8] at sys/dev/misc/musycc/musycc.c:167.

name is the netgraph hook name string, which ng_add_hook kmallocs with strlen(name)+1 (sys/netgraph/netgraph/ng_base.c:739) and which arrives bounded to NG_HOOKSIZ=32 bytes via the NGM_CONNECT/NGM_MKHOOK ourhook[NG_HOOKSIZ] field.

A valid configuration string such as ts1,2,3,4,5,6,7,8,9,10,11,12,13 (parse_ts accepts this: every token is 0..31, nbit=13, ts=0x3FFE, chan=1, ts&1==0 so it passes the framing check at musycc.c:1069) is 31 chars; ksprintf writes 32 bytes (31 + NUL), overrunning hookname by 24 bytes that span hook(8)+rx_drop(8)+tx_limit(8).

sch->hook is reassigned to the real hook at line 1085 and sch->tx_limit is reassigned at line 1086, but schan.rx_drop (offset 40 in struct schan) is only ever incremented post-allocation β€” it is never re-zeroed β€” so the low 8 bytes of rx_drop retain attacker-chosen ASCII.

Threat

Same attacker position as the primary finding (root or SYSCAP_RESTRICTEDROOT via ng_socket).

The persistent corruption is confined to a stats counter that is not actually printed back through any path in this file (status_chans prints tx_drop, tx_pending, txn, rxn, crc_error, etc. but not rx_drop), so the practical impact is essentially nil today β€” it is a latent heap-scribble defect rather than an exploitable vulnerability.

Reported as Low because the overrun is real and reproducible and any future code that adds rx_drop to the status output, or any shift in struct layout, would turn this into a live info-leak or pointer-corruption primitive.

Exploit / PoC

Demonstration only (impact is contained by subsequent reinit). As root on a host with a musycc node sync-0-5-0:

ngctl mkpeer sync-0-5-0: echo 'ts1,2,3,4,5,6,7,8,9,10,11,12,13' r

This calls musycc_newhook with name="ts1,2,3,4,5,6,7,8,9,10,11,12,13"; ksprintf writes 32 bytes into hookname[8] and clobbers hook/rx_drop/ tx_limit.

Verification under a kernel debugger: read schan->rx_drop for chan 1 and observe it is non-zero (= 0x312C30312C392C38 on little-endian, the bytes "8,9,10,1") before any packet has been received, proving the out-of-bounds write occurred.

Use a bounded copy. The hook name is already known to fit in NG_HOOKSIZ (32) so the destination must either be enlarged or the copy bounded:

--- a/sys/dev/misc/musycc/musycc.c
+++ b/sys/dev/misc/musycc/musycc.c
@@ -164,7 +164,7 @@ struct schan {
    int         chan;
    u_int32_t   ts;
-   char        hookname[8];
+   char        hookname[NG_HOOKSIZ];
    hook_p      hook;
@@ -1074,7 +1074,7 @@ musycc_newhook(node_p node, hook_p hook, const char *name)
        sch->chan = chan;
-       ksprintf(sch->hookname, name);  /* XXX overflow ? */
+       strlcpy(sch->hookname, name, sizeof(sch->hookname));
        sc->chan[chan] = sch;

Enlarging hookname to NG_HOOKSIZ (32) is the cleanest fix; strlcpy alone also closes the overrun.

  • DF-1499 (sibling): heap overflow in same file's status_chans.
  • DF-1501 (sibling): nchan > NPORT OOB attach.
  • DF-1502 (sibling): IRQ-vs-disconnect UAF.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1500 Β· 1 files
FileTypeDescriptionSize
VERDICT.md verdict verification verdict 994 B ↓ raw
VERDICT.md verdict verification verdict
↓ download raw

DF-1500 - Verification Verdict

Status: reproduced (reproduced=1) Impact: none Confidence: likely

Finding

Unbounded ksprintf into fixed 8-byte schan.hookname in musycc_newhook

Source Location

sys/dev/misc/musycc/musycc.c:167-1077

Verdict

Source-confirmed (complex fix): Unbounded ksprintf into fixed 8-byte schan.hookname in musycc_newhook. No diff in batch.

Fix Status

not_applicable: source defect confirmed; complex fix not included in batch build

Summary

musycc.c:1077 musycc_newhook: ksprintf(sch->hookname, name) / XXX overflow ? / into char hookname[8] (167). name is netgraph hook name, capped at NG_HOOKSIZ=32 bytes via NGM_CONNECT/NGM_MKHOOK ourhook[NG_HOOKSIZ]. ts1,2,3,4,5,6,7,8,9,10,11,12,13 = 31 chars -> ksprintf writes 32 bytes into hookname[8] overruns 24 bytes into hook/rx_drop/tx_limit. hook reassigned at 1085, tx_limit at 1086, but rx_drop never re-zeroed, holds attacker ASCII bytes. Confined to stats counter not exposed today -> lat

Fix verification

not_testable
baseline reproduced→ patch + rebuild →patched clean

source defect confirmed; complex fix not included in batch build

source defect confirmed; complex fix not included in batch build
combined build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none (Low severity)

Evidence (decisive lines)

Source-confirmed: musycc_newhook uses ksprintf into fixed 8-byte schan.hookname without bounds check, stack/heap overflow on long hook name. Complex fix (needs ksnprintf). HW-gated.

Verified recommended fix

Source-confirmed: musycc_newhook uses ksprintf into fixed 8-byte schan.hookname without bounds check, stack/heap overflow on long hook name. Complex fix (needs ksnprintf). HW-gated.

Verdict

Source-confirmed: musycc_newhook uses ksprintf into fixed 8-byte schan.hookname without bounds check, stack/heap overflow on long hook name. Complex fix (needs ksnprintf). HW-gated.