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
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
+79 -6
View File
@@ -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<unix::pid_t> {
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<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(
target_os = "macos",
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.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));
}
}