Skip to content

ext/ucred: Support PID in peer creds on macOS #79387

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 43 additions & 14 deletions library/std/src/sys/unix/ext/ucred.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,12 @@ pub struct UCred {
#[cfg(any(target_os = "android", target_os = "linux"))]
pub use self::impl_linux::peer_cred;

#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "openbsd"
))]
#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
pub use self::impl_bsd::peer_cred;

#[cfg(any(target_os = "macos", target_os = "ios",))]
pub use self::impl_mac::peer_cred;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod impl_linux {
use super::UCred;
Expand Down Expand Up @@ -73,13 +70,7 @@ pub mod impl_linux {
}
}

#[cfg(any(
target_os = "dragonfly",
target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "openbsd"
))]
#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
pub mod impl_bsd {
use super::UCred;
use crate::io;
Expand All @@ -95,3 +86,41 @@ pub mod impl_bsd {
}
}
}

#[cfg(any(target_os = "macos", target_os = "ios",))]
pub mod impl_mac {
use super::UCred;
use crate::os::unix::io::AsRawFd;
use crate::os::unix::net::UnixStream;
use crate::{io, mem};
use libc::{c_void, getpeereid, getsockopt, pid_t, socklen_t, LOCAL_PEERPID, SOL_LOCAL};

pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
let mut cred = UCred { uid: 1, gid: 1, pid: None };
unsafe {
let ret = getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);

if ret != 0 {
return Err(io::Error::last_os_error());
}

let mut pid: pid_t = 1;
let mut pid_size = mem::size_of::<pid_t>() as socklen_t;

let ret = getsockopt(
socket.as_raw_fd(),
SOL_LOCAL,
LOCAL_PEERPID,
&mut pid as *mut pid_t as *mut c_void,
&mut pid_size,
);

if ret == 0 && pid_size as usize == mem::size_of::<pid_t>() {
cred.pid = Some(pid);
Ok(cred)
} else {
Err(io::Error::last_os_error())
}
}
}
}
15 changes: 14 additions & 1 deletion library/std/src/sys/unix/ext/ucred/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::os::unix::net::UnixStream;
use libc::{getegid, geteuid};
use libc::{getegid, geteuid, getpid};

#[test]
#[cfg(any(
Expand All @@ -23,3 +23,16 @@ fn test_socket_pair() {
assert_eq!(cred_a.uid, uid);
assert_eq!(cred_a.gid, gid);
}

#[test]
#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos",))]
fn test_socket_pair_pids(arg: Type) -> RetType {
// Create two connected sockets and get their peer credentials.
let (sock_a, sock_b) = UnixStream::pair().unwrap();
let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap());

// On supported platforms (see the cfg above), the credentials should always include the PID.
let pid = unsafe { getpid() };
assert_eq!(cred_a.pid, Some(pid));
assert_eq!(cred_b.pid, Some(pid));
}