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.
Recommended fix
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.
Related findings
- DF-1499 (sibling): heap overflow in same file's
status_chans. - DF-1501 (sibling):
nchan > NPORTOOB attach. - DF-1502 (sibling): IRQ-vs-disconnect UAF.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1500 Β· 1 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | verification verdict | 994 B | β 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_testablesource defect confirmed; complex fix not included in batch build
source defect confirmed; complex fix not included in batch build
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.
No comments yet.