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

File refcount / unp_rights leak when ssb_appendcontrol fails on SOCK_STREAM SCM_RIGHTS

Summary

In uipc_send SOCK_STREAM/SEQPACKET control path when ssb_appendcontrol returns 0 (peer so_rcv no space) code silently leaves control and m non-NULL but never sets error. Post-switch cleanup if(control&&error!=0) unp_dispose(control) skips unp_dispose and m_freem(control) only frees mbuf releasing none of file references that unp_internalize acquired via fhold()+unp_add_right(). Leaked refs keep files and unp_rights inflated permanently enabling slow kernel-memory exhaustion. Any local user. [VERIFIED pass2: reproduced deterministic unpriv - SO_SNDBUF 1MB over SO_RCVBUF 4KB asymmetry gives 50-50 silent drops with inflight +400 permanent; UPGRADE Low to Medium (unpriv kernel-memory exhaustion plus silent stream loss); ENOBUFS fix A/B delta 0]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2560 Β· 3 files
FileTypeDescriptionSize
scm_leak6.c β€” 4.3 KB view raw
scm_leak5.c β€” 3.4 KB view raw
scm_leak3.c β€” 4.0 KB view raw

Fix verification

not_testable
↓ fix.diffper-fix-DF-2560

Confirmed kernel references

Detail

Evidence (decisive lines)

scm_leak6 run: success=50 fail=0; peer drained 16384 fill bytes only; inflight +400 after close-all; openfiles +8

PoC changes

4 rig generations; final deterministic SO_SNDBUF/SO_RCVBUF asymmetry trigger

Verified recommended fix

set error=ENOBUFS on append failure so the cleanup disposes the rights (in combined fix kernel)

Verdict

SOCK_STREAM SCM_RIGHTS branch (uipc_usrreq.c:766-787 + cleanup :808-814): when ssb_appendcontrol() fails, error stays 0, the cleanup skips unp_dispose(control) and m_freem()s it -- every fhold()/unp_add_right() leaks. DETERMINISTIC unprivileged repro (no race): the :767 macro checks the RECEIVERs hiwat while the :787 SSB_STOP backpressure and sosend pre-checks key off the SENDERs snd limits -- set SO_SNDBUF=1MB >> SO_RCVBUF=4KB, fill the receiver past its hiwat with plain data (sbappend is unconditional), then sendmsg(SCM_RIGHTS): 50/50 calls returned SUCCESS while the messages were silently dropped (peer drained exactly the fill bytes, none of the attack data) and net.local.inflight grew +400 (50 x 8 rights), kern.openfiles +8; the leak persisted after closing every descriptor.