From 08583d5ad48528261678df724deb0978d98a7b81 Mon Sep 17 00:00:00 2001 From: apio Date: Mon, 18 Sep 2023 07:19:53 +0200 Subject: [PATCH] kernel: Allow sending signals to process groups from userspace --- kernel/src/sys/signal.cpp | 65 ++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/kernel/src/sys/signal.cpp b/kernel/src/sys/signal.cpp index 779b151c..2d2d05c9 100644 --- a/kernel/src/sys/signal.cpp +++ b/kernel/src/sys/signal.cpp @@ -54,16 +54,65 @@ Result sys_kill(Registers*, SyscallArgs args) pid_t pid = (pid_t)args[0]; int signo = (int)args[1]; - // FIXME: Support this case. - if (pid <= 0) return err(ENOTSUP); + auto send_signal = [&](Thread* target) -> Result { + if (current->auth.euid != 0 && current->auth.euid != target->auth.euid && + current->auth.egid != target->auth.egid) + return err(EPERM); + if (target->is_kernel) return {}; + if (signo == 0) return {}; - auto* target = TRY(Result::from_option(Scheduler::find_by_pid(pid), ESRCH)); - if (current->auth.euid != 0 && current->auth.euid != target->auth.euid && current->auth.egid != target->auth.egid) - return err(EPERM); - if (target->is_kernel) return 0; - if (signo == 0) return 0; + target->send_signal(signo); - target->send_signal(signo); + return {}; + }; + + if (pid > 0) + { + auto* target = TRY(Result::from_option(Scheduler::find_by_pid(pid), ESRCH)); + TRY(send_signal(target)); + } + else if (pid == 0) + { + int errno = -1; + bool pgid_exists = false; + Scheduler::for_each_in_process_group(current->pgid, [&](Thread* target) { + pgid_exists = true; + auto rc = send_signal(target); + if (rc.has_error()) + { + errno = rc.error(); + return false; + } + return true; + }); + if (errno > 0) return err(errno); + if (!pgid_exists) return err(ESRCH); + } + else if (pid == -1) + { + for (auto* thread : g_threads) + { + // We ignore permission errors here. + if (thread != current && thread->id != 1) send_signal(thread); + } + } + else if (pid < -1) + { + int errno = -1; + bool pgid_exists = false; + Scheduler::for_each_in_process_group(-pid, [&](Thread* target) { + pgid_exists = true; + auto rc = send_signal(target); + if (rc.has_error()) + { + errno = rc.error(); + return false; + } + return true; + }); + if (errno > 0) return err(errno); + if (!pgid_exists) return err(ESRCH); + } return 0; }