DF-2713 / verdict.json
{ "finding_id": "DF-2713", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "Uninitialized CMSG_SPACE tail padding of every sbcreatecontrol()-built control message is copied to userspace by sys_recvmsg()'s per-mbuf copyout of m->m_len bytes; reproduced as unprivileged user maxx on the stock INVARIANTS kernel with deterministic attacker-planted content (2396-2400 marker bytes per 300-receive run in the same process, 4 marker bytes per run from a fork()ed process), and eliminated entirely by zeroing the padding (kernel #1 with fix.diff: 0 marker, 0 nonzero bytes in all phases).", "exploit_chain": "socket(AF_INET,SOCK_DGRAM) + setsockopt(IP_RECVTTL/IP_RECVTOS/IP_RECVDSTADDR); groom the per-CPU plain-mbuf objcache with failing sendmsg(2) calls whose 40-byte control buffer carries the marker (sys_sendmsg allocates a plain MT_CONTROL mbuf, copyins the bytes, sosend frees it via uipc_socket.c:1240); sendto/recvmsg on 127.0.0.1; read 18 stale heap bytes per receive from [CMSG_LEN(size), CMSG_SPACE(size)) of each cmsg. Repeatable without limit; discloses whatever any process last freed into the mbuf cache (packet payloads, control buffers of other users' sockets).", "evidence": [ "run.log: Phase B MARKER(0xCC)=2396/2400/2400 per 300-iter run + marker-hit hexdump '+00: 14 00 00 00 00 00 00 00 07 00 00 00 cc cc cc cc / +10: 7f 00 00 01 cc cc cc cc' (cc bytes in the IP_RECVDSTADDR padding right after the 127.0.0.1 data)", "run.2.log: Phase C XPROC-MARKER(0x5A)=4 in all 3 runs (fork()ed child's bytes in parent's padding)", "run.3.log: Phase B 1196/1668/2280 marker bytes (3rd execution, stability)", "fix_run.log: kernel #1 with fix.diff -> 0 marker and 0 nonzero padding bytes in all phases" ], "kernel_refs": [ "sys/kern/uipc_sockbuf.c:585", "sys/kern/uipc_sockbuf.c:595", "sys/kern/uipc_sockbuf.c:597", "sys/kern/uipc_sockbuf.c:599", "sys/kern/uipc_syscalls.c:1175", "sys/kern/uipc_syscalls.c:1182", "sys/kern/uipc_syscalls.c:1189", "sys/netinet/ip_input.c:2206", "sys/netinet/ip_input.c:2212", "sys/netinet/ip_input.c:2218", "sys/netinet6/ip6_input.c:1070", "sys/kern/uipc_usrreq.c:695" ], "poc_changes": "Rewrote the seed concept entirely: final PoC grooms the plain-mbuf objcache via FAILING sendmsg(2) control marshalling (EINVAL from unp_internalize frees the marker mbuf through sosend's error path) because AF_UNIX dgram data mbufs come from the pkthdr cache and never met the control-mbuf cache; UDP payload sized 1200B so the trigger packet itself uses clusters and does not consume plain mbufs.", "attempts": 4, "guest_uname": "DragonFly dfbsd 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": 1380, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o leak_cmsgpad leak_cmsgpad.c", "run_cmd": "./leak_cmsgpad", "code_hash": "477def9d189fd0e816322df8d38fc92f04e90a35179f86c451686d9d81b5f737", "notes": "Verified both directions: baseline leak on stock kernel (3 executions) and absence on single-fix kernel #1. Cross-process disclosure demonstrated in run.2.log Phase C. Same-class precedent: DF-0389 (rtsock sockaddr padding), DF-0010/DF-2557 (cmsgcred content) - this finding is the generic CMSG_SPACE tail padding at the recvmsg copyout sink, distinct from all three and from DF-2702 (SCM_RIGHTS MSG_PEEK raw pointers).", "recommended_fix": "bzero the full CMSG_SPACE(size) in sbcreatecontrol() before filling header/data (uipc_sockbuf.c:596).", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Mon Aug 31 04:46:23 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Applied fix.diff to the guest's /usr/src, make nativekernel + installkernel (kernel #1), rebooted, re-ran the identical PoC: 0 marker bytes and 0 nonzero padding bytes in all phases (fix_run.log) vs 2396-2400 marker bytes on baseline. Leak eliminated; no regressions observed during the run.", "fix_evidence": [ "fix_run.log", "fix.diff" ] } |