197 lines
5.2 KiB
C++
197 lines
5.2 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, ¤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<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];
|
|
|
|
auto send_signal = [&](Thread* target) -> Result<void> {
|
|
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<Thread*>::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<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;
|
|
}
|
|
|
|
Result<u64> 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<u64> 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);
|
|
}
|
|
}
|
|
}
|