Luna/kernel/src/sys/signal.cpp
apio a35ca0b367
All checks were successful
continuous-integration/drone/push Build is passing
libluna+kernel: Add Bitset and use it for signals
2023-08-23 10:51:02 +02:00

102 lines
2.9 KiB
C++

#include "Log.h"
#include "Pledge.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include <bits/signal.h>
Result<u64> 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<u64> 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, &current->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<u64> 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];
// FIXME: Support this case.
if (pid <= 0) return err(ENOTSUP);
auto* target = TRY(Result<Thread*>::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);
return 0;
}
Result<u64> 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;
}