{
  "finding_id": "DF-3366",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "leak",
  "confidence": "certain",
  "verdict": "Uninitialized/stale kernel heap bytes are disclosed to unprivileged local users through routing-socket replies. rt_setgate() allocates route keys/gateways at RT_ROUNDUP(sa_len) size (sys/net/route.c:1213-1223) but only sa_len bytes are initialized (route.c:925 bcopy; rt_maskedcopy route.c:1299-1304 zeroes only to sa_len), while rt_msg_buffer() copies the full rounded length back to userland (rtsock.c:1140-1141) and RTM_GET requires no privilege (rtsock.c:738-740). Any AF with sa_len%8!=0 (AF_INET6: 4-byte tail; AF_LINK/AF_MPLS: variable) leaks 1-7 stale M_RTABLE bytes per sockaddr. Reproduced on the stock INVARIANTS guest: a root-side groom planted marker 41 42 43 44 at key offset [28..32) of 32 to-be-freed 64-byte route-key chunks; after free+realloc, unprivileged user maxx (uid 1001) read the marker back in the DST sockaddr padding of RTM_GET 2001:db8:99::1 replies \u2014 5/5 deterministic runs \u2014 proving cross-object stale-heap disclosure. Baseline boot-time routes show zero pads only because fresh pages are zeroed. Fix validated by in-guest kernel rebuild: with the two zero-the-padding hunks applied, the same groom+read yields 00 00 00 00 (5/5) with no functional regression.",
  "exploit_chain": "unpriv user: socket(PF_ROUTE) -> RTM_GET <any inet6 route> -> parse reply sockaddrs -> bytes [sa_len..RT_ROUNDUP(sa_len)) are stale kernel heap. Cross-object proof: root (any routing daemon / route(8) churn) sprays routes with marker-tainted key tails, frees them; the next route created reuses the chunk; unpriv RTM_GET discloses the marker. Enables silent harvesting of recycled routing-state fragments by any local user.",
  "evidence": [
    "findings/poc/DF-3366/run.log \u2014 decisive: unpriv RTM_GET 2001:db8:99::1 -> RTAX[0] pad 41 42 43 44, 5/5 runs, uid=1001(maxx)",
    "findings/poc/DF-3366/groom.log \u2014 root groom: spray 32/32 (marker keys), delete 32/32, victim added",
    "findings/poc/DF-3366/run.baseline.log \u2014 unpriv ::1 baseline (zero pads from zeroed boot pages; channel exercised)",
    "findings/poc/DF-3366/fix_validation.log \u2014 patched kernel #1: same groom, pads 00 00 00 00 5/5",
    "findings/poc/DF-3366/fix.diff \u2014 validated fix (route.c: key-tail zero; gateway exact-length copy + tail zero)"
  ],
  "kernel_refs": [
    "sys/net/route.c:1213-1223",
    "sys/net/route.c:920-925",
    "sys/net/route.c:1285-1305",
    "sys/net/route.c:1226-1227",
    "sys/net/rtsock.c:1134-1143",
    "sys/net/rtsock.c:738-740",
    "sys/net/rtsock.c:1023"
  ],
  "poc_changes": "seed concept reworked: original sketch had no runnable code. Fixed inet_pton form (marker dsts need :: compression), non-blocking PF_ROUTE reads with poll+drain (rcvbuf flooded by broadcast replies), 28-byte delete form (rn_match compares min(clen) so tails never block deletion), gateway switched to a global on-link prefix (link-local gw needs KAME scope embedding).",
  "attempts": 4,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "runtime_sec": 420,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -Wall -o leak_get leak_get.c && cc -O2 -Wall -o groom groom.c",
  "run_cmd": "run_root ./groom ; run_user ./leak_get 2001:db8:99::1 5",
  "code_hash": "leak_get.c cea2d88acb97ec0c57575ed0aabcb58a90c619e61e0883727b85f83b7490fa34; groom.c 20765ce51e25d9c5ec56b2c7d8ba8784be7045c9a0bd22fb9d97d4fd5a95b96e",
  "notes": "Adjacent same-class surface NOT fixed here: rt_msg_buffer/rt_msg_mbuf also copy RTA_IFP/RTA_IFA sockaddrs rounded (link-level sdl pre-rounded by if.c:568, AF_INET=16 -> safe; embedded AF_INET6 ifaddr sockaddrs expose 4 adjacent in-struct bytes). rt_setgates rounded source read (old bcopy(gate,gw,glen)) also read <=7 bytes past an unpadded final message sockaddr; the fixs exact-length copy removes that too.",
  "recommended_fix": "Zero sockaddr alignment padding when storing route keys and gateways (route.c:925-after, route.c:1227): bcopy only sa_len valid bytes and bzero the RT_ROUNDUP remainder.",
  "fix_status": "fixed",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Fri Sep 11 13:29:21 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff (2 hunks in sys/net/route.c) applied to guest /usr/src; make -j6 nativekernel + installkernel + reboot; identical groom sequence runs clean (32/32 adds, victim created) and the unprivileged RTM_GET pads are 00 00 00 00 (5/5) vs 41 42 43 44 (5/5) on stock. Leak eliminated, no functional regression.",
  "fix_evidence": "findings/poc/DF-3366/fix_validation.log (patched run), fix_uname.txt (patched kernel identity), run.log (baseline), fix.diff"
}