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

CBQ cbq_getqstats() copies out uninitialized kernel stack: stats.handle and stats.red[3] never initialized (DF-0438's twin)

Summary

cbq_getqstats() declares an uninitialized stack class_stats_t (264 bytes) and copies the whole struct to userspace; get_class_stats() never writes stats.handle (first 4 bytes) and never writes stats.red[3] (last 168 bytes) for droptail queues - red[] is only filled for Q_RED/Q_RIO. Guest-verified on stock kernel: handle=0x809af7ee (kernel pointer fragment) stable across 3 runs and red[3] dense with 64-bit kernel pointers (0xfffff881..., 0xfffff801...) - ~172 bytes of kernel stack per call. Exact twin of accepted DF-0438 (hfsc redstats); the CBQ copy of the KAME bug was never fixed. Root-to-root leak (DIOCGETQSTATS needs /dev/pf) hence Low; matters for the kernel/user information boundary. Fix validated (bzero + set handle): handle=2 (real qid), red[3] all zero.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3386 Β· 9 files
FileTypeDescriptionSize
cbq_stats_leak.c poc-source CBQ config via ioctls + DIOCGETQSTATS x3 6.7 KB view raw
run.log run-log baseline dumps: kernel pointers in handle/red[3] 3.5 KB view raw
run.fixed.log run-log fixed-kernel dumps: zeros + real handle 3.5 KB view raw
leak_sample.txt leak-sample copy of baseline leak dumps 3.5 KB view raw
fix.diff fix bzero stats + set handle 532 B view raw
env.txt env unames, struct sizes 870 B view raw
build.sh build compile command 102 B view raw
run.sh run run script with expected outputs 114 B view raw
build.log build-log build command record 185 B view raw

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched reproduced

Fixed kernel (#1, bzero + handle assignment via the same rebuilt kernel that validated DF-3385): baseline leaked handle=0x809af7ee + pointer-dense red[3] across 3 runs; patched run shows handle=0x00000002 (deterministic real qid) and red[3] entirely zero while scalar stats (depth/priority/qmax/ns_per_byte/qcnt) remain correct. Leak eliminated.

findings/poc/DF-3386/run.fixed.log vs run.log (before/after dumps)
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Fri Sep 11 23:03:53 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64

Confirmed kernel references

Detail

Evidence (decisive lines)

run.log / leak_sample.txt (baseline: 3 dumps with kernel pointers; handle 0x809af7ee x3); run.fixed.log (fixed: zeros + real handle); VERDICT.md

PoC changes

Written fresh for this finding (no seed); mirrors the proven DF-0441 ioctl driver pattern.

Verified recommended fix

bzero the stats struct in cbq_getqstats() and set stats.handle from cl->stats_.handle in get_class_stats()

Verdict

cbq_getqstats() copies out a 264-byte stack class_stats_t whose handle (4 bytes) and red[3] (168 bytes) are never initialized for droptail classes. Baseline: handle=0x809af7ee (kernel pointer fragment) stable across 3 runs and red[3] dense with 64-bit kernel pointers (0xfffff881..., 0xfffff801...) in every run. Fixed kernel (#1 with bzero+handle fix): handle=2 (the real class qid) and red[3] all zeros while all scalar stats remain correct. Root-to-root leak (DIOCGETQSTATS needs /dev/pf), Low severity, twin of accepted DF-0438.