asterinas/kernel/src/syscall/pidfd_getfd.rs

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 _))
}