Kernel heap info leak via uninitialized rt_msghdr.rtm_inits in NET_RT_DUMP sysctl: no M_ZERO on buffer
Summary
rttable_walkarg_create(:1676) kmalloc(w_bufsz,M_TEMP,M_WAITOK|M_NULLOK) WITHOUT M_ZERO. rt_msg_buffer(:1127-1130) only sets rtm_version/type/msglen. rttable_walk_entry(:1795-1801) sets flags/use/rmx/index/errno/pid/seq/addrs but NEVER sets rtm_inits (u_long ~8 bytes at offset ~32). 2 bytes struct padding between rtm_index(u_short offset 4) and rtm_flags(int offset 8) also unwritten. Buffer passed to SYSCTL_OUT(:1855) verbatim. sysctl NET_RT_DUMP is CTLFLAG_RD no priv check(:1884 only blocks writes). Any unpriv local user collects stale M_TEMP heap bytes (~10/route entry) useful for KASLR bypass.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0388 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| df_0388_leak.c | trigger-source | unprivileged sysctl(NET_RT_DUMP) reader that dumps rtm_inits + index/flags pad | 4.6 KB | view raw |
| build.sh | build-script | cc -O2 -Wall -o df_0388_leak df_0388_leak.c | 106 B | view raw |
| run.sh | run-script | unprivileged run | 222 B | view raw |
| README.md | readme | bug summary + reach + build/run/expected | 2.2 KB | β raw |
| leak_sample.txt | leak-sample | 5 iterations on baseline showing variance: 0xffffffffffff7f7c, 0x0100007f01db0610, 0x5254, ... | 1.7 KB | view raw |
| run.log | run-log | baseline full PoC output, leaked kernel pointers visible | 2.3 KB | view raw |
| fix.diff | suggested-fix | add M_ZERO to kmalloc in rttable_walkarg_create | 906 B | view raw |
| fix_run.log | run-log | patched-kernel run: rtm_inits=0 and pad=0 across 3 iterations | 1.0 KB | view raw |
| env.txt | environment | uname + cc version | 247 B | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-0388 β Kernel heap info leak via uninitialized rt_msghdr in NET_RT_DUMP
Bug
w->w_buf = kmalloc(w->w_bufsz, M_TEMP, M_WAITOK | M_NULLOK); /* NO M_ZERO */
The buffer is then partially filled: rt_msg_buffer writes rtm_msglen /
rtm_version / rtm_type (first 4 bytes); rttable_walk_entry
(rtsock.c:1795-1801) writes rtm_flags, rtm_use, rtm_rmx, rtm_index,
rtm_errno, rtm_pid, rtm_seq, rtm_addrs. The following fields of
struct rt_msghdr (sys/net/route.h:211) are never written:
rtm_initsβu_longat offset 32 (8 bytes on 64-bit)- 2 bytes of struct padding between
rtm_index(u_short @ off 4) andrtm_flags(int @ off 8)
These unwritten bytes are emitted verbatim by SYSCTL_OUT(req, w->w_buf, ...)
(rtsock.c:1855). Because the kmalloc lacks M_ZERO, the bytes carry stale
M_TEMP slab residue from whatever allocation previously occupied that memory.
sysctl_rtsock is registered CTLFLAG_RD (rtsock.c:1928) β the only
privilege check (:1884) blocks writes (req->newptr). Any unprivileged
local user can dump routes and harvest the stale bytes.
Reach (one sysctl from any user)
sysctl(NET/PF_ROUTE/0/af/NET_RT_DUMP/0) /* read, unprivileged */
or equivalently any process doing RTM_GET over the routing socket. The PoC
uses sysctl(2) so no socket privilege is required at all.
Build / Run
cc -O2 -Wall -o df_0388_leak df_0388_leak.c ./df_0388_leak # any user; runs the dump 4x with slab perturbation
Expected (bug present)
rtm_inits != 0for at least one record per dump.- The OR of all
rtm_initsvalues varies across runs/dumps (different slab residue each time), and frequently contains kernel pointers (0x01db06xx,0x08993950,0xffffffffffff7f7cβ¦) and IPv4 addresses (0x0100007fβ¦= 127.0.0.1). - The 2 bytes of index/flags padding also come up non-zero (
0x5254"RT",0x0021β¦).
Expected (fix present)
rtm_initsis0x0000000000000000for every record in every dump.- The index/flags padding is
0x0000everywhere.
Preconditions
None β NET_RT_DUMP is unprivileged. Module/kernel: base rtsock.c (no
kldload).
Fix verification
fixedvalidated
see evidence pack
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
REPRODUCED (live). rttable_walkarg_create kmalloc no M_ZERO -> rtm_inits+pad leak stale slab via routing socket sysctl. Unprivileged.
No comments yet.