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)
PoC verification
Evidence pack
findings/poc/DF-3386 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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
fixedFixed 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)
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.
No comments yet.