Uninitialized kernel stack leaked via priq_getqstats copyout of struct priq_classstats
| Field | Value |
|---|---|
| ID | DF-0658 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N |
| CWE | CWE-200 Exposure of Sensitive Information |
| File | sys/net/altq/altq_priq.c |
| Lines | 221 (uninit decl); 609-627 (partial fill); 251 (copyout) |
| Area | net/altq (PRIQ statistics) |
| Confidence | certain |
| Discovered | 2026-07-02 |
| Reported | pending |
Cross-reference: Identical pattern to DF-0652 (cbq) and DF-0592 (fairq). All three ALTQ schedulers have the same uninit-stack-leak in their
getqstatshandler.
Summary
priq_getqstats declares struct priq_classstats stats on the kernel
stack without zeroing (line 221). get_class_stats only populates the
scalar fields and conditionally red[0]/red[0..2]; the 4-byte compiler
padding between qtype and red[0] plus the entire 168-byte red[3]
array remain uninitialized for the default Q_DROPTAIL configuration.
copyout(&stats, ubuf, sizeof(stats)) at line 251 then leaks ~172 bytes
of stale kernel stack to userspace per DIOCGETQSTATS call.
Root cause
altq_priq.c:221: struct priq_classstats stats; on the stack, no
memset. get_class_stats (altq_priq.c:609-627) writes scalar fields
but:
- 4-byte padding at off 52-55 (between qtype and red[0]): never
written by anyone.
- red[3] (168 bytes, off 56-223): never written for the default
Q_DROPTAIL (line 354). Even with Q_RED, red_getstats fills only
red[0]; red[1]/red[2] stay uninitialized.
copyout at line 251 copies the full 224 bytes unconditionally.
Threat model & preconditions
- Privilege: root (or
/dev/pf-granted; mode 0600root:wheel). - Impact: ~172 bytes of kernel stack per call β may contain kernel pointers (KASLR bypass), credential pointers, or other sensitive locals.
- Same one-line fix as DF-0652/DF-0592:
memset(&stats, 0, sizeof(stats)).
Recommended fix
--- a/sys/net/altq/altq_priq.c
+++ b/sys/net/altq/altq_priq.c
@@ -218,6 +218,8 @@
struct ifaltq *ifq;
int error = 0;
+ memset(&stats, 0, sizeof(stats));
+
if (*nbytes < sizeof(stats))
return (EINVAL);
References
sys/net/altq/altq_priq.c:221β uninitializedstats.sys/net/altq/altq_priq.c:609-627βget_class_statspartial fill.sys/net/altq/altq_priq.c:251βcopyout.- DF-0652 (cbq), DF-0592 (fairq) β same pattern.
Timeline
- 2026-07-02 Discovered during automated DragonFlyBSD kernel security audit.
- 2026-07-02 Reported to DragonFlyBSD security contact (pending).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0658 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | bzero the stats struct before get_class_stats fills it. | 302 B | view raw |
| VERDICT.md | verdict | source-confirmation + fix | 1.0 KB | β raw |
| ../_batch_low/fix_build.log | build-log | combined 80-fix kernel build (rc=0, -Werror) | 5.6 MB | β download |
| ../_batch_low/combined_all.patch | suggested-fix | all 80 fixes batched | 20.0 KB | view raw |
| ../_batch_low/env.txt | environment | guest uname + kern.version | 247 B | view raw |
DF-0658 β Low-severity source-confirmation
Verdict: REPRODUCED
Impact: leak Confidence: certain
Kernel ref: sys/net/altq/altq_priq.c:221
Mechanism / why
Source-confirmed: priq_getqstats declares struct priq_classstats stats on the stack unzeroed; get_class_stats fills only scalar fields; full struct copied to user -> stack leak. altq (GENERIC).
Recommended fix
bzero the stats struct before get_class_stats fills it.
Phase 8 (combined build)
All 80 Low-severity fixes were batched into one patch (../_batch_low/combined_all.patch) and applied to the in-guest /usr/src. A single make -j6 nativekernel KERNCONF=X86_64_GENERIC completed rc=0 with 0 errors under -Werror (../_batch_low/fix_build.log). The GENERIC-compiled fixes (net/radix, netinet, netinet6, wlan, wlan_ccmp, wlan_wep, altq, if_mib) are build-validated; module-only/netgraph/ipfw3/netsmb/vlan/sl/disc fixes apply cleanly to source (those subsystems are optional, not compiled into GENERIC).
A standalone git apply-able fix.diff is in this folder.
Fix verification
fixedcombined 80-fix patch builds rc=0 under -Werror on GENERIC (X86_64_GENERIC #1); GENERIC-compiled fixes build-validated, module-only fixes apply cleanly to source.
baseline 6.5-DEVELOPMENT #0 (Jul 2) -> patched build #1 (Jul 23) rc=0 -Werror, 0 errors
Confirmed kernel references
- s
- y
- s
- /
- n
- e
- t
- /
- a
- l
- t
- q
- /
- a
- l
- t
- q
- _
- p
- r
- i
- q
- .
- c
- :
- 2
- 2
- 1
Detail
Exploit chain
none (Low-severity leak; source-only confirmation)
Evidence (decisive lines)
DF-0658 [REPRODUCED] - sys/net/altq/altq_priq.c:221
PoC changes
fix.diff present in findings/poc/DF-0658/; batched into ../_batch_low/combined_all.patch
Verified recommended fix
bzero the stats struct before get_class_stats fills it.
Verdict
Source-confirmed: priq_getqstats declares struct priq_classstats stats on the stack unzeroed; get_class_stats fills only scalar fields; full struct copied to user -> stack leak. altq (GENERIC).
No comments yet.