#include "Log.h" #include "Pledge.h" #include "memory/MemoryManager.h" #include "sys/Syscall.h" #include "thread/Scheduler.h" #include Result sys_sigreturn(Registers* regs, SyscallArgs) { auto* current = Scheduler::current(); current->sigreturn(regs); // Since we could be returning to anywhere in the program, we don't want to be changing the return value register // (RAX on x86_64). But our syscall framework doesn't allow that, so we just set it to its current value. return current->return_register(); } Result sys_sigaction(Registers*, SyscallArgs args) { auto* current = Scheduler::current(); TRY(check_pledge(current, Promise::p_stdio)); int signo = (int)args[0]; const struct sigaction* act = (const struct sigaction*)args[1]; struct sigaction* oldact = (struct sigaction*)args[2]; void* sigreturn = (void*)args[3]; if (signo > NSIG) return err(EINVAL); if (signo <= 0) return err(EINVAL); if (oldact) { if (!MemoryManager::copy_to_user_typed(oldact, ¤t->signal_handlers[signo - 1])) return err(EFAULT); } if (act) { struct sigaction kact; if (!MemoryManager::copy_from_user_typed(act, &kact)) return err(EFAULT); kact.__sa_sigreturn = sigreturn; current->signal_handlers[signo - 1] = kact; } return 0; } Result sys_kill(Registers*, SyscallArgs args) { auto* current = Scheduler::current(); TRY(check_pledge(current, Promise::p_proc)); pid_t pid = (pid_t)args[0]; int signo = (int)args[1]; 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 {}; 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; } Result sys_sigprocmask(Registers*, SyscallArgs args) { auto* current = Scheduler::current(); TRY(check_pledge(current, Promise::p_stdio)); int how = (int)args[0]; const sigset_t* set = (const sigset_t*)args[1]; sigset_t* oldset = (sigset_t*)args[2]; if (oldset) { sigset_t mask = current->signal_mask.value(); if (!MemoryManager::copy_to_user_typed(oldset, &mask)) return err(EFAULT); } if (set) { sigset_t kset; if (!MemoryManager::copy_from_user_typed(set, &kset)) return err(EFAULT); switch (how) { case SIG_BLOCK: current->signal_mask = current->signal_mask.value() | kset; break; case SIG_UNBLOCK: current->signal_mask = current->signal_mask.value() & ~kset; break; case SIG_SETMASK: current->signal_mask = kset; break; default: return err(EINVAL); } } return 0; } Result sys_pause(Registers* regs, SyscallArgs) { auto* current = Scheduler::current(); while (1) { kernel_wait_for_event(); if (current->interrupted) { if (current->will_ignore_pending_signal()) { current->process_pending_signals(regs); continue; } return err(EINTR); } } } Result sys_sigsuspend(Registers* regs, SyscallArgs args) { const sigset_t* set = (const sigset_t*)args[0]; auto* current = Scheduler::current(); sigset_t kset; if (!MemoryManager::copy_from_user_typed(set, &kset)) return err(EFAULT); sigset_t oldset = current->signal_mask.value(); current->signal_mask = kset; while (1) { kernel_wait_for_event(); if (current->interrupted) { if (current->will_ignore_pending_signal()) { current->process_pending_signals(regs); continue; } current->signal_mask = oldset; return err(EINTR); } } }