Skip to content

Commit 87f07d4

Browse files
authored
Add pidfd_getfd syscall. (#681)
1 parent 1ca79bf commit 87f07d4

File tree

4 files changed

+93
-8
lines changed

4 files changed

+93
-8
lines changed

src/backend/libc/process/syscalls.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::backend::conv::{syscall_ret, syscall_ret_u32};
1515
#[cfg(not(target_os = "wasi"))]
1616
use crate::fd::BorrowedFd;
1717
#[cfg(target_os = "linux")]
18-
use crate::fd::{AsRawFd, OwnedFd};
18+
use crate::fd::{AsRawFd, OwnedFd, RawFd};
1919
#[cfg(feature = "fs")]
2020
use crate::ffi::CStr;
2121
#[cfg(feature = "fs")]
@@ -33,7 +33,10 @@ use crate::process::{Resource, Rlimit};
3333
use crate::process::{WaitId, WaitidOptions, WaitidStatus};
3434
use core::mem::MaybeUninit;
3535
#[cfg(target_os = "linux")]
36-
use {crate::backend::conv::syscall_ret_owned_fd, crate::process::PidfdFlags};
36+
use {
37+
super::super::conv::syscall_ret_owned_fd, crate::process::PidfdFlags,
38+
crate::process::PidfdGetfdFlags,
39+
};
3740

3841
#[cfg(feature = "fs")]
3942
#[cfg(not(target_os = "wasi"))]
@@ -517,6 +520,22 @@ pub(crate) fn pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result<OwnedFd> {
517520
}
518521
}
519522

523+
#[cfg(target_os = "linux")]
524+
pub(crate) fn pidfd_getfd(
525+
pidfd: BorrowedFd<'_>,
526+
targetfd: RawFd,
527+
flags: PidfdGetfdFlags,
528+
) -> io::Result<OwnedFd> {
529+
unsafe {
530+
syscall_ret_owned_fd(c::syscall(
531+
c::SYS_pidfd_getfd,
532+
pidfd,
533+
targetfd,
534+
flags.bits(),
535+
))
536+
}
537+
}
538+
520539
#[cfg(not(target_os = "wasi"))]
521540
pub(crate) fn getgroups(buf: &mut [Gid]) -> io::Result<usize> {
522541
let len = buf.len().try_into().map_err(|_| io::Errno::NOMEM)?;

src/backend/linux_raw/process/syscalls.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ use crate::backend::c;
1111
#[cfg(feature = "fs")]
1212
use crate::backend::conv::slice_mut;
1313
use crate::backend::conv::{
14-
by_mut, by_ref, c_int, c_uint, negative_pid, pass_usize, ret, ret_c_int, ret_c_int_infallible,
15-
ret_c_uint, ret_infallible, ret_owned_fd, ret_usize, size_of, slice_just_addr,
16-
slice_just_addr_mut, zero,
14+
by_mut, by_ref, c_int, c_uint, negative_pid, pass_usize, raw_fd, ret, ret_c_int,
15+
ret_c_int_infallible, ret_c_uint, ret_infallible, ret_owned_fd, ret_usize, size_of,
16+
slice_just_addr, slice_just_addr_mut, zero,
1717
};
18-
use crate::fd::{AsRawFd, BorrowedFd, OwnedFd};
18+
use crate::fd::{AsRawFd, BorrowedFd, OwnedFd, RawFd};
1919
#[cfg(feature = "fs")]
2020
use crate::ffi::CStr;
2121
use crate::io;
2222
use crate::pid::{RawNonZeroPid, RawPid};
2323
use crate::process::{
24-
Cpuid, Gid, MembarrierCommand, MembarrierQuery, Pid, PidfdFlags, Resource, Rlimit, Uid, WaitId,
25-
WaitOptions, WaitStatus, WaitidOptions, WaitidStatus,
24+
Cpuid, Gid, MembarrierCommand, MembarrierQuery, Pid, PidfdFlags, PidfdGetfdFlags, Resource,
25+
Rlimit, Uid, WaitId, WaitOptions, WaitStatus, WaitidOptions, WaitidStatus,
2626
};
2727
use crate::signal::Signal;
2828
use crate::utils::as_mut_ptr;
@@ -600,6 +600,22 @@ pub(crate) fn test_kill_current_process_group() -> io::Result<()> {
600600
unsafe { ret(syscall_readonly!(__NR_kill, pass_usize(0), pass_usize(0))) }
601601
}
602602

603+
#[inline]
604+
pub(crate) fn pidfd_getfd(
605+
pidfd: BorrowedFd<'_>,
606+
targetfd: RawFd,
607+
flags: PidfdGetfdFlags,
608+
) -> io::Result<OwnedFd> {
609+
unsafe {
610+
ret_owned_fd(syscall_readonly!(
611+
__NR_pidfd_getfd,
612+
pidfd,
613+
raw_fd(targetfd),
614+
c_int(flags.bits() as _)
615+
))
616+
}
617+
}
618+
603619
#[inline]
604620
pub(crate) fn pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result<OwnedFd> {
605621
unsafe { ret_owned_fd(syscall_readonly!(__NR_pidfd_open, pid, flags)) }

src/process/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ mod kill;
1414
mod membarrier;
1515
#[cfg(target_os = "linux")]
1616
mod pidfd;
17+
#[cfg(target_os = "linux")]
18+
mod pidfd_getfd;
1719
#[cfg(linux_kernel)]
1820
mod prctl;
1921
#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] // WASI doesn't have [gs]etpriority.
@@ -44,6 +46,8 @@ pub use kill::*;
4446
pub use membarrier::*;
4547
#[cfg(target_os = "linux")]
4648
pub use pidfd::*;
49+
#[cfg(target_os = "linux")]
50+
pub use pidfd_getfd::*;
4751
#[cfg(linux_kernel)]
4852
pub use prctl::*;
4953
#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]

src/process/pidfd_getfd.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#![allow(unsafe_code)]
2+
use crate::fd::OwnedFd;
3+
use crate::{backend, io};
4+
use backend::fd::{AsFd, RawFd};
5+
6+
/// Raw file descriptor in another process.
7+
///
8+
/// A distinct type alias is used here to inform the user that normal file descriptors from the
9+
/// calling process should not be used. The provided file descriptor is used by the kernel as the
10+
/// index into the file descriptor table of an entirely different process.
11+
pub type ForeignRawFd = RawFd;
12+
13+
bitflags::bitflags! {
14+
/// All flags are reserved for future use.
15+
pub struct PidfdGetfdFlags: backend::c::c_uint {}
16+
}
17+
18+
/// `syscall(SYS_pidfd_getfd, pidfd, flags)`—Obtain a duplicate of another
19+
/// process's file descriptor.
20+
///
21+
/// # References
22+
/// - [Linux]
23+
///
24+
/// # Warning
25+
///
26+
/// This function is generally safe for the calling process, but it can impact the target process
27+
/// in unexpected ways. If you want to ensure that Rust I/O safety assumptions continue to hold in
28+
/// the target process, then the target process must have communicated the file description number
29+
/// to the calling process from a value of a type that implements AsRawFd, and the target process
30+
/// must not drop that value until after the calling process has returned from `pidfd_getfd`.
31+
///
32+
/// When `pidfd_getfd` is used to debug the target, or the target is not a Rust aplication, or
33+
/// `pidfd_getfd` is used in any other way, then extra care should be taken to avoid unexpected
34+
/// behaviour or crashes.
35+
///
36+
/// For further details, see the references above.
37+
///
38+
/// [Linux]: https://man7.org/linux/man-pages/man2/pidfd_getfd.2.html
39+
#[inline]
40+
pub fn pidfd_getfd<Fd: AsFd>(
41+
pidfd: Fd,
42+
targetfd: ForeignRawFd,
43+
flags: PidfdGetfdFlags,
44+
) -> io::Result<OwnedFd> {
45+
backend::process::syscalls::pidfd_getfd(pidfd.as_fd(), targetfd, flags)
46+
}

0 commit comments

Comments
 (0)