Handle negative P(G)IDs via cast_(un)signed

This commit is contained in:
Ruihan Li 2025-05-01 23:51:37 +08:00 committed by Jianfeng Jiang
parent d3e4f175cd
commit 50ba735e96
5 changed files with 50 additions and 29 deletions

View File

@ -14,6 +14,7 @@
#![feature(fn_traits)] #![feature(fn_traits)]
#![feature(format_args_nl)] #![feature(format_args_nl)]
#![feature(int_roundings)] #![feature(int_roundings)]
#![feature(integer_sign_cast)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(linked_list_cursors)] #![feature(linked_list_cursors)]
#![feature(linked_list_remove)] #![feature(linked_list_remove)]

View File

@ -1,7 +1,5 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
#![expect(dead_code)]
use super::{Pgid, Pid}; use super::{Pgid, Pid};
use crate::prelude::*; use crate::prelude::*;
@ -13,44 +11,50 @@ pub enum ProcessFilter {
} }
impl ProcessFilter { impl ProcessFilter {
// used for waitid // For `waitpid`.
pub fn from_which_and_id(which: u64, id: u64) -> Result<Self> { pub fn from_which_and_id(which: u64, id: u32) -> Result<Self> {
// Does not support PID_FD now(which = 3) // Reference:
// https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/wait.h#L20 // <https://elixir.bootlin.com/linux/v6.14.4/source/include/uapi/linux/wait.h#L16-L20>
const P_ALL: u64 = 0;
const P_PID: u64 = 1;
const P_PGID: u64 = 2;
const P_PIDFD: u64 = 3;
match which { match which {
0 => Ok(ProcessFilter::Any), P_ALL => Ok(ProcessFilter::Any),
1 => Ok(ProcessFilter::WithPid(id as Pid)), P_PID => Ok(ProcessFilter::WithPid(id)),
2 => Ok(ProcessFilter::WithPgid(id as Pgid)), P_PGID => Ok(ProcessFilter::WithPgid(id)),
3 => todo!(), P_PIDFD => {
_ => return_errno_with_message!(Errno::EINVAL, "invalid which"), warn!("the process filter `P_PIDFD` is not supported");
return_errno_with_message!(
Errno::EINVAL,
"the process filter `P_PIDFD` is not supported"
);
}
_ => return_errno_with_message!(Errno::EINVAL, "the process filter is invalid"),
} }
} }
// used for wait4 and kill // For `wait4` and `kill`.
pub fn from_id(wait_pid: i32) -> Self { pub fn from_id(wait_pid: i32) -> Self {
// https://man7.org/linux/man-pages/man2/waitpid.2.html // Reference:
// https://man7.org/linux/man-pages/man2/kill.2.html // <https://man7.org/linux/man-pages/man2/waitpid.2.html>
// <https://man7.org/linux/man-pages/man2/kill.2.html>
if wait_pid < -1 { if wait_pid < -1 {
// process group ID is equal to the absolute value of pid. // "wait for any child process whose process group ID is equal to the absolute value of
ProcessFilter::WithPgid((-wait_pid) as Pgid) // `pid`"
ProcessFilter::WithPgid((-wait_pid).cast_unsigned())
} else if wait_pid == -1 { } else if wait_pid == -1 {
// wait for any child process // "wait for any child process"
ProcessFilter::Any ProcessFilter::Any
} else if wait_pid == 0 { } else if wait_pid == 0 {
// wait for any child process with same process group ID // "wait for any child process whose process group ID is equal to that of the calling
// process at the time of the call to `waitpid()`"
let pgid = current!().pgid(); let pgid = current!().pgid();
ProcessFilter::WithPgid(pgid) ProcessFilter::WithPgid(pgid)
} else { } else {
// pid > 0. wait for the child whose process ID is equal to the value of pid. // "wait for the child whose process ID is equal to the value of `pid`"
ProcessFilter::WithPid(wait_pid as Pid) ProcessFilter::WithPid(wait_pid.cast_unsigned())
}
}
pub fn contains_pid(&self, pid: Pid) -> bool {
match self {
ProcessFilter::Any => true,
ProcessFilter::WithPid(filter_pid) => *filter_pid == pid,
ProcessFilter::WithPgid(_) => todo!(),
} }
} }
} }

View File

@ -12,6 +12,10 @@ pub fn sys_setpgid(pid: Pid, pgid: Pgid, ctx: &Context) -> Result<SyscallReturn>
// The documentation quoted below is from // The documentation quoted below is from
// <https://www.man7.org/linux/man-pages/man2/setpgid.2.html>. // <https://www.man7.org/linux/man-pages/man2/setpgid.2.html>.
if pid.cast_signed() < 0 || pgid.cast_signed() < 0 {
return_errno_with_message!(Errno::EINVAL, "negative PIDs or PGIDs are not valid");
}
// "If `pid` is zero, then the process ID of the calling process is used." // "If `pid` is zero, then the process ID of the calling process is used."
let pid = if pid == 0 { current.pid() } else { pid }; let pid = if pid == 0 { current.pid() } else { pid };
// "If `pgid` is zero, then the PGID of the process specified by `pid` is made the same as its // "If `pgid` is zero, then the PGID of the process specified by `pid` is made the same as its

View File

@ -15,14 +15,16 @@ pub fn sys_waitid(
ctx: &Context, ctx: &Context,
) -> Result<SyscallReturn> { ) -> Result<SyscallReturn> {
// FIXME: what does infoq and rusage use for? // FIXME: what does infoq and rusage use for?
let process_filter = ProcessFilter::from_which_and_id(which, upid)?; let process_filter = ProcessFilter::from_which_and_id(which, upid as _)?;
let wait_options = WaitOptions::from_bits(options as u32) let wait_options = WaitOptions::from_bits(options as u32)
.ok_or(Error::with_message(Errno::EINVAL, "invalid options"))?; .ok_or(Error::with_message(Errno::EINVAL, "invalid options"))?;
let waited_process = let waited_process =
wait_child_exit(process_filter, wait_options, ctx).map_err(|err| match err.error() { wait_child_exit(process_filter, wait_options, ctx).map_err(|err| match err.error() {
Errno::EINTR => Error::new(Errno::ERESTARTSYS), Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err, _ => err,
})?; })?;
let pid = waited_process.map_or(0, |process| process.pid()); let pid = waited_process.map_or(0, |process| process.pid());
Ok(SyscallReturn::Return(pid as _)) Ok(SyscallReturn::Return(pid as _))
} }

View File

@ -32,6 +32,10 @@ END_SETUP()
FN_TEST(setpgid_invalid) FN_TEST(setpgid_invalid)
{ {
// Negative PIDs or PGIDs
TEST_ERRNO(setpgid(-1, current), EINVAL);
TEST_ERRNO(setpgid(current, -1), EINVAL);
// Non-present process groups // Non-present process groups
TEST_ERRNO(setpgid(child1, child2), EPERM); TEST_ERRNO(setpgid(child1, child2), EPERM);
TEST_ERRNO(setpgid(child2, child1), EPERM); TEST_ERRNO(setpgid(child2, child1), EPERM);
@ -176,6 +180,9 @@ END_TEST()
FN_TEST(getpgid_invalid) FN_TEST(getpgid_invalid)
{ {
// Negative PIDs
TEST_ERRNO(getpgid(-1), ESRCH);
// Non-present processes // Non-present processes
TEST_ERRNO(getpgid(0x3c3c3c3c), ESRCH); TEST_ERRNO(getpgid(0x3c3c3c3c), ESRCH);
} }
@ -183,6 +190,9 @@ END_TEST()
FN_TEST(getsid_invalid) FN_TEST(getsid_invalid)
{ {
// Negative PIDs
TEST_ERRNO(getsid(-1), ESRCH);
// Non-present processes // Non-present processes
TEST_ERRNO(getsid(0x3c3c3c3c), ESRCH); TEST_ERRNO(getsid(0x3c3c3c3c), ESRCH);
} }