From ab3c1ac937a5a9701936d4dbf126b6588b6abaec Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 10 Jun 2025 20:22:51 -0700 Subject: [PATCH] Add `socket_peerpidfd` Supported on Linux since 6.5. --- src/backend/libc/net/sockopt.rs | 9 ++++++++- src/backend/linux_raw/net/sockopt.rs | 8 +++++++- src/net/sockopt.rs | 11 ++++++++++- tests/event/select.rs | 2 ++ tests/net/unix_alloc.rs | 23 +++++++++++++++++++++++ 5 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/backend/libc/net/sockopt.rs b/src/backend/libc/net/sockopt.rs index 132ebe758..487ff6415 100644 --- a/src/backend/libc/net/sockopt.rs +++ b/src/backend/libc/net/sockopt.rs @@ -3,7 +3,7 @@ use super::ext::{in6_addr_new, in_addr_new}; use crate::backend::c; use crate::backend::conv::{borrowed_fd, ret}; -use crate::fd::BorrowedFd; +use crate::fd::{BorrowedFd, FromRawFd, OwnedFd, RawFd}; #[cfg(feature = "alloc")] #[cfg(any( linux_like, @@ -1060,6 +1060,13 @@ pub(crate) fn socket_peercred(fd: BorrowedFd<'_>) -> io::Result { getsockopt(fd, c::SOL_SOCKET, c::SO_PEERCRED) } +#[cfg(linux_kernel)] +#[inline] +pub(crate) fn socket_peerpidfd(fd: BorrowedFd<'_>) -> io::Result { + let raw = getsockopt::(fd, c::SOL_SOCKET, c::SO_PEERPIDFD)?; + Ok(unsafe { OwnedFd::from_raw_fd(raw) }) +} + #[cfg(target_os = "linux")] #[inline] pub(crate) fn set_xdp_umem_reg(fd: BorrowedFd<'_>, value: XdpUmemReg) -> io::Result<()> { diff --git a/src/backend/linux_raw/net/sockopt.rs b/src/backend/linux_raw/net/sockopt.rs index 3e5ea1fd8..fdc503edb 100644 --- a/src/backend/linux_raw/net/sockopt.rs +++ b/src/backend/linux_raw/net/sockopt.rs @@ -7,7 +7,7 @@ use crate::backend::c; use crate::backend::conv::{by_mut, c_uint, ret, socklen_t}; -use crate::fd::BorrowedFd; +use crate::fd::{BorrowedFd, FromRawFd, OwnedFd, RawFd}; #[cfg(feature = "alloc")] use crate::ffi::CStr; use crate::io; @@ -848,6 +848,12 @@ pub(crate) fn socket_peercred(fd: BorrowedFd<'_>) -> io::Result { getsockopt(fd, c::SOL_SOCKET, linux_raw_sys::net::SO_PEERCRED) } +#[inline] +pub(crate) fn socket_peerpidfd(fd: BorrowedFd<'_>) -> io::Result { + let raw = getsockopt::(fd, c::SOL_SOCKET, linux_raw_sys::net::SO_PEERPIDFD)?; + Ok(unsafe { OwnedFd::from_raw_fd(raw) }) +} + #[cfg(target_os = "linux")] #[inline] pub(crate) fn set_xdp_umem_reg(fd: BorrowedFd<'_>, value: XdpUmemReg) -> io::Result<()> { diff --git a/src/net/sockopt.rs b/src/net/sockopt.rs index ef8176aea..29407bb8c 100644 --- a/src/net/sockopt.rs +++ b/src/net/sockopt.rs @@ -183,7 +183,7 @@ use crate::{backend, io}; ))] use alloc::string::String; use backend::c; -use backend::fd::AsFd; +use backend::fd::{AsFd, OwnedFd}; use core::time::Duration; /// Timeout identifier for use with [`set_socket_timeout`] and @@ -1536,6 +1536,15 @@ pub fn socket_peercred(fd: Fd) -> io::Result { backend::net::sockopt::socket_peercred(fd.as_fd()) } +///`getsockopt(fd, SOL_SOCKET, SO_PEERPIDFD)`—Get pidfd of Unix domain peer +/// +/// Added in Linux 6.5. +#[cfg(linux_kernel)] +#[doc(alias = "SO_PEERPIDFD")] +pub fn socket_peerpidfd(fd: Fd) -> io::Result { + backend::net::sockopt::socket_peerpidfd(fd.as_fd()) +} + /// `setsockopt(fd, SOL_XDP, XDP_UMEM_REG, value)` /// /// On kernel versions only supporting v1, the flags are ignored. diff --git a/tests/event/select.rs b/tests/event/select.rs index 6bdec54a0..aaec963b7 100644 --- a/tests/event/select.rs +++ b/tests/event/select.rs @@ -88,6 +88,7 @@ fn test_select_with_pipes() { #[serial] // for `setrlimit` usage fn test_select_with_great_fds() { use core::cmp::max; + use rustix::fd::{FromRawFd as _, OwnedFd}; use rustix::io::{read, write}; use rustix::pipe::pipe; use rustix::process::{getrlimit, setrlimit, Resource}; @@ -277,6 +278,7 @@ fn test_select_with_sockets() { #[test] #[serial] // for `setrlimit` usage, and `crate::init` fn test_select_with_maxfd_sockets() { + use rustix::fd::{FromRawFd as _, OwnedFd}; use rustix::net::{recv, send, AddressFamily, RecvFlags, SendFlags, SocketType}; use rustix::process::{getrlimit, setrlimit, Resource}; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; diff --git a/tests/net/unix_alloc.rs b/tests/net/unix_alloc.rs index 3e0774e7d..e18ff47bc 100644 --- a/tests/net/unix_alloc.rs +++ b/tests/net/unix_alloc.rs @@ -677,6 +677,29 @@ fn test_unix_peercred() { }; } +#[cfg(all(feature = "process", feature = "net", linux_kernel))] +#[test] +fn test_unix_peerpidfd() { + use rustix::net::{sockopt, AddressFamily, SocketFlags, SocketType}; + use rustix::process::PidfdFlags; + + let (send_sock, _recv_sock) = rustix::net::socketpair( + AddressFamily::UNIX, + SocketType::STREAM, + SocketFlags::CLOEXEC, + None, + ) + .unwrap(); + let pidfd = sockopt::socket_peerpidfd(&send_sock).unwrap(); + let own_pidfd = + rustix::process::pidfd_open(rustix::process::getpid(), PidfdFlags::empty()).unwrap(); + // Two pidfds refer to the same process iff their `st_ino` values are the same. + assert_eq!( + rustix::fs::fstat(pidfd).unwrap().st_ino, + rustix::fs::fstat(own_pidfd).unwrap().st_ino + ) +} + /// Like `test_unix_msg_with_scm_rights`, but with multiple file descriptors /// over multiple control messages. #[cfg(not(any(target_os = "redox", target_os = "wasi")))]