net: implement UCred::pid on FreeBSD (#8086)

This commit is contained in:
HueCodes
2026-05-03 10:28:31 +02:00
committed by GitHub
parent 0926ab195a
commit e77885a494
3 changed files with 118 additions and 7 deletions
+8 -1
View File
@@ -1,4 +1,4 @@
316 323
& &
+ +
< <
@@ -189,14 +189,17 @@ mutex
Mutex Mutex
Nagle Nagle
namespace namespace
NetBSD
nonblocking nonblocking
nondecreasing nondecreasing
noop noop
ntasks ntasks
NTO
NUMA NUMA
ok ok
oneshot oneshot
opcode opcode
OpenBSD
ORed ORed
os os
parker parker
@@ -213,6 +216,7 @@ RAII
RCU RCU
reallocations reallocations
recv's recv's
Redox
refactors refactors
refcount refcount
refcounting refcounting
@@ -279,6 +283,7 @@ tokio's
Tokio's Tokio's
tuple tuple
Tuple Tuple
tvOS
tx tx
udp udp
UDP UDP
@@ -306,6 +311,7 @@ vec
versa versa
versioned versioned
versioning versioning
visionOS
vtable vtable
waker waker
wakers wakers
@@ -313,5 +319,6 @@ Wakers
wakeup wakeup
wakeups wakeups
WASI WASI
watchOS
workstealing workstealing
ZST ZST
+79 -6
View File
@@ -24,8 +24,10 @@ impl UCred {
/// Gets PID (process ID) of the process. /// Gets PID (process ID) of the process.
/// ///
/// This is only implemented under Linux, Android, iOS, macOS, Solaris, /// This is implemented under Linux, Android, OpenBSD, FreeBSD (since
/// Illumos and Cygwin. On other platforms this will always return `None`. /// 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<unix::pid_t> { pub fn pid(&self) -> Option<unix::pid_t> {
self.pid self.pid
} }
@@ -44,8 +46,11 @@ pub(crate) use self::impl_linux::get_peer_cred;
#[cfg(any(target_os = "netbsd", target_os = "nto"))] #[cfg(any(target_os = "netbsd", target_os = "nto"))]
pub(crate) use self::impl_netbsd::get_peer_cred; pub(crate) use self::impl_netbsd::get_peer_cred;
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] #[cfg(target_os = "dragonfly")]
pub(crate) use self::impl_bsd::get_peer_cred; pub(crate) use self::impl_dragonfly::get_peer_cred;
#[cfg(target_os = "freebsd")]
pub(crate) use self::impl_freebsd::get_peer_cred;
#[cfg(any( #[cfg(any(
target_os = "macos", target_os = "macos",
@@ -172,8 +177,8 @@ pub(crate) mod impl_netbsd {
} }
} }
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] #[cfg(target_os = "dragonfly")]
pub(crate) mod impl_bsd { pub(crate) mod impl_dragonfly {
use crate::net::unix::{self, UnixStream}; use crate::net::unix::{self, UnixStream};
use libc::getpeereid; 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<super::UCred> {
// `SOL_LOCAL` is not re-exported by `libc` for FreeBSD; it is defined
// as 0 in `<sys/un.h>`.
const SOL_LOCAL: libc::c_int = 0;
unsafe {
let raw_fd = sock.as_raw_fd();
let mut xucred = MaybeUninit::<xucred>::zeroed();
let mut len = size_of::<xucred>() 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::<xucred>() {
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( #[cfg(any(
target_os = "macos", target_os = "macos",
target_os = "ios", target_os = "ios",
+31
View File
@@ -23,4 +23,35 @@ async fn test_socket_pair() {
assert_eq!(cred_a.uid(), uid); assert_eq!(cred_a.uid(), uid);
assert_eq!(cred_a.gid(), gid); 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));
}
} }