diff --git a/spellcheck.dic b/spellcheck.dic index 0cf8ae850..ea6ab93ae 100644 --- a/spellcheck.dic +++ b/spellcheck.dic @@ -1,4 +1,4 @@ -316 +323 & + < @@ -189,14 +189,17 @@ mutex Mutex Nagle namespace +NetBSD nonblocking nondecreasing noop ntasks +NTO NUMA ok oneshot opcode +OpenBSD ORed os parker @@ -213,6 +216,7 @@ RAII RCU reallocations recv's +Redox refactors refcount refcounting @@ -279,6 +283,7 @@ tokio's Tokio's tuple Tuple +tvOS tx udp UDP @@ -306,6 +311,7 @@ vec versa versioned versioning +visionOS vtable waker wakers @@ -313,5 +319,6 @@ Wakers wakeup wakeups WASI +watchOS workstealing ZST diff --git a/tokio/src/net/unix/ucred.rs b/tokio/src/net/unix/ucred.rs index f77befb06..a268bad1b 100644 --- a/tokio/src/net/unix/ucred.rs +++ b/tokio/src/net/unix/ucred.rs @@ -24,8 +24,10 @@ impl UCred { /// Gets PID (process ID) of the process. /// - /// This is only implemented under Linux, Android, iOS, macOS, Solaris, - /// Illumos and Cygwin. On other platforms this will always return `None`. + /// This is implemented under Linux, Android, OpenBSD, FreeBSD (since + /// FreeBSD 13), NetBSD, NTO, iOS, macOS, tvOS, watchOS, visionOS, + /// Solaris, Illumos, Cygwin, Haiku, and Redox. On other platforms this + /// will always return `None`. pub fn pid(&self) -> Option { self.pid } @@ -44,8 +46,11 @@ pub(crate) use self::impl_linux::get_peer_cred; #[cfg(any(target_os = "netbsd", target_os = "nto"))] pub(crate) use self::impl_netbsd::get_peer_cred; -#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] -pub(crate) use self::impl_bsd::get_peer_cred; +#[cfg(target_os = "dragonfly")] +pub(crate) use self::impl_dragonfly::get_peer_cred; + +#[cfg(target_os = "freebsd")] +pub(crate) use self::impl_freebsd::get_peer_cred; #[cfg(any( target_os = "macos", @@ -172,8 +177,8 @@ pub(crate) mod impl_netbsd { } } -#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] -pub(crate) mod impl_bsd { +#[cfg(target_os = "dragonfly")] +pub(crate) mod impl_dragonfly { use crate::net::unix::{self, UnixStream}; use libc::getpeereid; @@ -203,6 +208,74 @@ pub(crate) mod impl_bsd { } } +#[cfg(target_os = "freebsd")] +pub(crate) mod impl_freebsd { + use crate::net::unix::{self, UnixStream}; + + use libc::{c_void, getsockopt, socklen_t, xucred, LOCAL_PEERCRED, XUCRED_VERSION}; + use std::io; + use std::mem::{size_of, MaybeUninit}; + use std::os::unix::io::AsRawFd; + + pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result { + // `SOL_LOCAL` is not re-exported by `libc` for FreeBSD; it is defined + // as 0 in ``. + const SOL_LOCAL: libc::c_int = 0; + + unsafe { + let raw_fd = sock.as_raw_fd(); + + let mut xucred = MaybeUninit::::zeroed(); + let mut len = size_of::() as socklen_t; + + let ret = getsockopt( + raw_fd, + SOL_LOCAL, + LOCAL_PEERCRED, + xucred.as_mut_ptr() as *mut c_void, + &mut len, + ); + + if ret != 0 { + return Err(io::Error::last_os_error()); + } + if len as usize != size_of::() { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "unexpected xucred size from LOCAL_PEERCRED", + )); + } + + let xucred = xucred.assume_init(); + + // Match `getpeereid(3)` and reject any `xucred` whose version we + // don't know how to interpret. + if xucred.cr_version != XUCRED_VERSION { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "unexpected xucred version from LOCAL_PEERCRED", + )); + } + + // `cr_pid` is populated by the kernel since FreeBSD 13. PID 0 is + // the kernel scheduler and never a real userland peer, so we + // surface it as `None` rather than a misleading `Some(0)`. + let pid = match xucred.cr_pid__c_anonymous_union.cr_pid { + 0 => None, + p => Some(p as unix::pid_t), + }; + + // `xucred` carries the effective uid in `cr_uid` and the effective + // gid in `cr_groups[0]`, matching what `getpeereid(2)` returns. + Ok(super::UCred { + uid: xucred.cr_uid as unix::uid_t, + gid: xucred.cr_groups[0] as unix::gid_t, + pid, + }) + } + } +} + #[cfg(any( target_os = "macos", target_os = "ios", diff --git a/tokio/tests/uds_cred.rs b/tokio/tests/uds_cred.rs index 4f08d764e..7da49b455 100644 --- a/tokio/tests/uds_cred.rs +++ b/tokio/tests/uds_cred.rs @@ -23,4 +23,35 @@ async fn test_socket_pair() { assert_eq!(cred_a.uid(), uid); assert_eq!(cred_a.gid(), gid); + + // On platforms where `UCred::pid` is implemented and the kernel + // populates it, both ends of a `socketpair` must report the current + // process's PID. + // + // FreeBSD COMPAT32 (32-bit binary on a 64-bit kernel) leaves `cr_pid` + // zeroed pending FreeBSD bug 294833; the assertion is gated on 64-bit + // FreeBSD until that fix ships. + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "openbsd", + all(target_os = "freebsd", target_pointer_width = "64"), + target_os = "netbsd", + target_os = "nto", + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + target_os = "visionos", + target_os = "solaris", + target_os = "illumos", + target_os = "redox", + target_os = "haiku", + target_os = "cygwin", + ))] + { + let pid = unsafe { libc::getpid() }; + assert_eq!(cred_a.pid(), Some(pid)); + assert_eq!(cred_b.pid(), Some(pid)); + } }