diff --git a/src/backend/libc/net/sockopt.rs b/src/backend/libc/net/sockopt.rs index 2320255d7..d1c7b05f6 100644 --- a/src/backend/libc/net/sockopt.rs +++ b/src/backend/libc/net/sockopt.rs @@ -4,6 +4,8 @@ use super::ext::{in6_addr_new, in_addr_new}; use crate::backend::c; use crate::backend::conv::{borrowed_fd, ret}; use crate::fd::BorrowedFd; +#[cfg(all(linux_kernel, not(target_os = "android")))] +use crate::fd::{FromRawFd, OwnedFd, RawFd}; #[cfg(feature = "alloc")] #[cfg(any( linux_like, @@ -1094,6 +1096,13 @@ pub(crate) fn socket_peercred(fd: BorrowedFd<'_>) -> io::Result { getsockopt(fd, c::SOL_SOCKET, c::SO_PEERCRED) } +#[cfg(all(linux_kernel, not(target_os = "android")))] +#[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(all(target_os = "linux", feature = "time"))] #[inline] pub(crate) fn set_txtime( diff --git a/src/backend/linux_raw/net/sockopt.rs b/src/backend/linux_raw/net/sockopt.rs index 85c65b085..a553bc1f7 100644 --- a/src/backend/linux_raw/net/sockopt.rs +++ b/src/backend/linux_raw/net/sockopt.rs @@ -9,7 +9,7 @@ use crate::backend::c; use crate::backend::conv::{by_mut, c_uint, ret, socklen_t}; #[cfg(all(target_os = "linux", feature = "time"))] use crate::clockid::ClockId; -use crate::fd::BorrowedFd; +use crate::fd::{BorrowedFd, FromRawFd, OwnedFd, RawFd}; #[cfg(feature = "alloc")] use crate::ffi::CStr; use crate::io; @@ -880,6 +880,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(all(target_os = "linux", feature = "time"))] #[inline] pub(crate) fn set_txtime( diff --git a/src/net/sockopt.rs b/src/net/sockopt.rs index a3f3ed59d..0ee511e2c 100644 --- a/src/net/sockopt.rs +++ b/src/net/sockopt.rs @@ -188,6 +188,8 @@ use crate::{backend, io}; use alloc::string::String; use backend::c; use backend::fd::AsFd; +#[cfg(all(linux_kernel, not(target_os = "android")))] +use backend::fd::OwnedFd; use core::time::Duration; /// Timeout identifier for use with [`set_socket_timeout`] and @@ -1692,6 +1694,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(all(linux_kernel, not(target_os = "android")))] +#[doc(alias = "SO_PEERPIDFD")] +pub fn socket_peerpidfd(fd: Fd) -> io::Result { + backend::net::sockopt::socket_peerpidfd(fd.as_fd()) +} + /// `getsockopt(fd, SOL_SOCKET, SO_TXTIME)` — Get transmission timing configuration. #[cfg(all(target_os = "linux", feature = "time"))] #[doc(alias = "SO_TXTIME")] diff --git a/tests/event/select.rs b/tests/event/select.rs index 13b502a34..c47c099ba 100644 --- a/tests/event/select.rs +++ b/tests/event/select.rs @@ -89,6 +89,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}; @@ -278,6 +279,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 49a5f854d..8ba41a264 100644 --- a/tests/net/unix_alloc.rs +++ b/tests/net/unix_alloc.rs @@ -684,6 +684,34 @@ fn test_unix_peercred() { }; } +#[cfg(all( + feature = "process", + feature = "net", + linux_kernel, + not(target_os = "android") +))] +#[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")))]