unix-ancillary-0.2.0 has been yanked.
unix-ancillary
Safe, ergonomic Unix socket ancillary data (SCM_RIGHTS file descriptor passing) for Rust.
Features
- Safe
OwnedFd/BorrowedFdAPI — no raw file descriptors in the public API - Automatic cleanup — received FDs are
OwnedFd, closed on drop - No fd leaks on truncation — the high-level API sizes the receive cmsg buffer past every Unix kernel's per-message fd cap. Surplus fds beyond the caller's
Nare auto-closed; truncation cannot leak fds into the process - CLOEXEC errors surfaced — if
fcntl(FD_CLOEXEC)fails on macOS, every received fd is closed and the error is returned - Ergonomic extension traits —
send_fds()/recv_fds()onUnixStreamandUnixDatagram
Quick Start
use UnixStream;
use UnixStreamExt;
let = pair.unwrap;
// Send a file descriptor
let file = open.unwrap;
tx.send_fds.unwrap;
// Receive it
let recv = rx..unwrap;
assert_eq!;
assert_eq!;
// recv.fds[0] is an OwnedFd — automatically closed on drop
Bring-your-own buffer
use UnixStream;
use UnixStreamExt;
let = pair.unwrap;
let mut buf = ;
let = rx..unwrap;
Low-Level API
use ;
use IoSlice;
use AsFd;
let file = open.unwrap;
let mut buf = vec!;
let mut ancillary = new;
ancillary.add_fds.unwrap;
How fd-leak protection works
Linux hard-codes SCM_MAX_FD = 253 per SCM_RIGHTS message; other Unix
kernels enforce comparable per-message caps. The high-level recv_fds
allocates a cmsg buffer sized for that cap regardless of the caller's N.
Result:
- A peer cannot send more fds than our buffer can hold — their kernel rejects
the
sendmsgfirst. - Every fd the receiving kernel deposits is wrapped in
OwnedFdimmediately. - Caller gets the first
N; the rest drop and close on the spot. Zero leak. - If
MSG_CTRUNCsomehow fires anyway, every extracted fd is closed and an error is returned — caller never sees partial state.
Low-level callers using SocketAncillary directly manage their own buffer
and must size it correctly; the is_truncated() flag is exposed for that
path.
CLOEXEC race on macOS
macOS lacks MSG_CMSG_CLOEXEC. This crate sets FD_CLOEXEC via fcntl
immediately after recvmsg returns, but a concurrent fork+exec between
the two calls can leak the fd into the child. If your workload forks
concurrently with fd-receiving threads, hold a fork lock around the receive.
Platform Support
- Linux — full support with
MSG_CMSG_CLOEXEC - macOS — supported with
fcntlCLOEXEC fallback (see caveat above) - FreeBSD, OpenBSD, NetBSD, DragonFly — supported with
MSG_CMSG_CLOEXEC
License
MIT