73 lines
2.4 KiB
Rust
73 lines
2.4 KiB
Rust
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
use crate::{
|
|
fs::file_table::{FdFlags, FileDesc, get_file_fast},
|
|
prelude::*,
|
|
process::{PidFile, credentials::capabilities::CapSet, posix_thread::AsPosixThread},
|
|
syscall::SyscallReturn,
|
|
};
|
|
|
|
pub fn sys_pidfd_getfd(
|
|
pidfd: FileDesc,
|
|
targetfd: FileDesc,
|
|
flags: u32,
|
|
ctx: &Context,
|
|
) -> Result<SyscallReturn> {
|
|
// The `flags` argument is reserved for future use. Currently, it must be specified as 0.
|
|
if flags != 0 {
|
|
return_errno_with_message!(Errno::EINVAL, "invalid flags");
|
|
}
|
|
debug!(
|
|
"pidfd_getfd: pidfd={}, targetfd={}, flags={}",
|
|
pidfd, targetfd, flags
|
|
);
|
|
|
|
let mut file_table = ctx.thread_local.borrow_file_table_mut();
|
|
let file = get_file_fast!(&mut file_table, pidfd);
|
|
let Some(pid_file) = file.downcast_ref::<PidFile>() else {
|
|
return_errno_with_message!(Errno::EBADF, "the file is not a PID file");
|
|
};
|
|
|
|
let process = pid_file
|
|
.process_opt()
|
|
.ok_or_else(|| Error::with_message(Errno::ESRCH, "the target process has been reaped"))?;
|
|
|
|
// The calling process should have PTRACE_MODE_ATTACH_REALCREDS permissions (see ptrace(2))
|
|
// over the process referred to by `pidfd`.
|
|
// Currently, this is implemented as requiring the calling process to have the
|
|
// CAP_SYS_PTRACE capability, which is stricter.
|
|
// TODO: Implement appropriate PTRACE_MODE_ATTACH_REALCREDS permission check.
|
|
if process
|
|
.user_ns()
|
|
.lock()
|
|
.check_cap(CapSet::SYS_PTRACE, ctx.posix_thread)
|
|
.is_err()
|
|
{
|
|
return_errno_with_message!(
|
|
Errno::EPERM,
|
|
"the calling process does not have the required permissions"
|
|
);
|
|
}
|
|
|
|
let main_thread = process.main_thread();
|
|
|
|
// Get the file description corresponding to to the file descriptor `targetfd` in the process
|
|
// referred to by the PID file.
|
|
let target_file_table = main_thread.as_posix_thread().unwrap().file_table();
|
|
let target_file = target_file_table
|
|
.lock()
|
|
.as_ref()
|
|
.ok_or_else(|| Error::with_message(Errno::ESRCH, "the target process has exited"))?
|
|
.read()
|
|
.get_file(targetfd)?
|
|
.clone();
|
|
|
|
// Duplicate the file descriptor into the caller's file descriptor table.
|
|
let new_fd = {
|
|
let mut file_table_locked = file_table.unwrap().write();
|
|
file_table_locked.insert(target_file, FdFlags::CLOEXEC)
|
|
};
|
|
|
|
Ok(SyscallReturn::Return(new_fd as _))
|
|
}
|