From 8970ddd9be6c013ff8cae2b1872f65348c7ded54 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Mon, 12 Aug 2024 22:05:00 -0400 Subject: kernel: Add initial support for signals Signed-off-by: Ian Moffett --- sys/kern/kern_exec.c | 4 +- sys/kern/kern_fork.c | 2 + sys/kern/kern_sched.c | 1 + sys/kern/kern_sig.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++ sys/kern/kern_stub.c | 33 +++++++ 5 files changed, 296 insertions(+), 1 deletion(-) create mode 100644 sys/kern/kern_sig.c (limited to 'sys/kern') diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index ceb08f6..863f4ae 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -97,9 +98,10 @@ execve(struct proc *td, const struct execve_args *args) prog.envp = args->envp; stack_top = td->stack_base + (PROC_STACK_SIZE - 1); - /* Setup registers and stack */ + /* Setup registers, signals and stack */ md_td_stackinit(td, (void *)(stack_top + VM_HIGHER_HALF), &prog); setregs(td, &prog, stack_top); + signals_init(td); /* Done, reset flags and start the user thread */ td->flags &= ~PROC_EXEC; diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 037026b..7bcff4b 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,7 @@ fork1(struct proc *cur, int flags, void(*ip)(void), struct proc **newprocp) *newprocp = newproc; newproc->pid = ++nthreads; + signals_init(newproc); sched_enqueue_td(newproc); done: if (status != 0) diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c index 6d85330..5f2b019 100644 --- a/sys/kern/kern_sched.c +++ b/sys/kern/kern_sched.c @@ -187,6 +187,7 @@ sched_switch(struct trapframe *tf) td = ci->curtd; if (td != NULL) { + dispatch_signals(td); td_pri_update(td); } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c new file mode 100644 index 0000000..ed29397 --- /dev/null +++ b/sys/kern/kern_sig.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define sigmask(SIGNO) BIT(SIGNO) + +static struct sigaction sa_tab[] = { + [SIGFPE] = { + .sa_handler = sigfpe_default, + .sa_mask = 0, + .sa_flags = 0, + .sa_sigaction = NULL + }, + + [SIGKILL] = { + .sa_handler = sigkill_default, + .sa_mask = 0, + .sa_flags = 0, + .sa_sigaction = NULL + }, + + [SIGSEGV] = { + .sa_handler = sigsegv_default, + .sa_mask = 0, + .sa_flags = 0, + .sa_sigaction = NULL + }, +}; + +/* + * Register a new signal descriptor, set it in the process + * structure and return it in `ksig`. + * + * @td: Process to register signal to. + * @signo: Signal number to register. + * @ksig: Will contain a pointer to new signal descriptor. + */ +int +newsig(struct proc *td, int signo, struct ksiginfo **ksig) +{ + struct ksiginfo *ksig_tmp; + + /* Ensure we have valid args */ + if (td == NULL || signo >= PROC_SIGMAX) + return -EINVAL; + + /* + * Make sure we have a valid signal list. If we already + * have a signal registered in a slot, free up memory used + * for that signal descriptor so we can override it with the + * new one. + */ + if (td->ksig_list == NULL) + return -EIO; + if ((ksig_tmp = td->ksig_list[signo]) != NULL) + dynfree(ksig_tmp); + + /* Allocate our new signal */ + ksig_tmp = dynalloc(sizeof(*ksig_tmp)); + if (ksig_tmp == NULL) + return -ENOMEM; + + memset(ksig_tmp, 0, sizeof(*ksig_tmp)); + ksig_tmp->signo = signo; + td->ksig_list[signo] = ksig_tmp; + *ksig = ksig_tmp; + return 0; +} + +/* + * Remove a signal from the signal table. + * + * @td: Process to remove signal from. + * @signo: Signal to remove. + */ +int +delsig(struct proc *td, int signo) +{ + struct ksiginfo *ksig_tmp; + + /* Ensure we have valid args */ + if (td == NULL || signo >= PROC_SIGMAX) + return -EINVAL; + + /* Don't do anything if it doesn't exist */ + if ((ksig_tmp = td->ksig_list[signo]) == NULL) + return 0; + + dynfree(ksig_tmp); + td->ksig_list[signo] = NULL; + return 0; +} + +int +sendsig(struct proc *td, const sigset_t *set) +{ + struct ksiginfo *ksig_tmp; + + /* Ensure arguments are correct */ + if (td == NULL || set == NULL) + return -EINVAL; + + /* Enqueue required ksiginfo structures */ + for (int i = 0; i < PROC_SIGMAX; ++i) { + if ((ksig_tmp = td->ksig_list[i]) == NULL) { + continue; + } + + /* Enqueue if it is a member of the sigset */ + if (sigismember(set, i)) { + spinlock_acquire(&td->ksigq_lock); + TAILQ_INSERT_TAIL(&td->ksigq, ksig_tmp, link); + spinlock_release(&td->ksigq_lock); + } + } + + return 0; +} + +int +signals_init(struct proc *td) +{ + struct sigaction *sa; + struct ksiginfo *ksig; + int error, i; + + TAILQ_INIT(&td->ksigq); + + /* Populate process signal table with defaults */ + for (i = 0; i < NELEM(sa_tab); ++i) { + sa = &sa_tab[i]; + + /* Drop actions that aren't set up */ + if (sa->sa_handler == NULL && sa->sa_sigaction == NULL) { + continue; + } + + /* Attempt to register the new signal */ + if ((error = newsig(td, i, &ksig)) != 0) { + goto fail; + } + + ksig->si = sa; + } + + return 0; + +fail: + /* + * We do not want the process signal table to be in + * an inconsistent state so we clean up on failure. + */ + for (int j = 0; j < i; ++j) { + if ((error = delsig(td, j)) != 0) { + kprintf("delsig() failed on signal %d (returned %d)\n", + j, error); + } + } + + return error; +} + +void +dispatch_signals(struct proc *td) +{ + struct ksiginfo *ksig_tmp; + struct sigaction *action; + + spinlock_acquire(&td->ksigq_lock); + while (!TAILQ_EMPTY(&td->ksigq)) { + /* Dequeue signal descriptor */ + ksig_tmp = TAILQ_FIRST(&td->ksigq); + TAILQ_REMOVE(&td->ksigq, ksig_tmp, link); + + /* Invoke handler */ + action = ksig_tmp->si; + action->sa_handler(ksig_tmp->signo); + } + + spinlock_release(&td->ksigq_lock); +} + +int +sigemptyset(sigset_t *set) +{ + *set = 0; + return 0; +} + +int +sigfillset(sigset_t *set) +{ + *set = ~(sigset_t)0; + return 0; +} + +int +sigaddset(sigset_t *set, int signo) +{ + if (signo <= 0 || signo >= PROC_SIGMAX) + return -EINVAL; + + *set |= sigmask(signo); + return 0; +} + +int +sigdelset(sigset_t *set, int signo) +{ + if (signo <= 0 || signo >= PROC_SIGMAX) + return -EINVAL; + + *set &= ~sigmask(signo); + return 0; +} + +int +sigismember(const sigset_t *set, int signo) +{ + if (signo <= 0 || signo >= PROC_SIGMAX) + return -EINVAL; + + return (*set & sigmask(signo)) != 0; +} diff --git a/sys/kern/kern_stub.c b/sys/kern/kern_stub.c index 65688e2..5a53cc1 100644 --- a/sys/kern/kern_stub.c +++ b/sys/kern/kern_stub.c @@ -30,6 +30,39 @@ #include #include #include +#include +#include +#include + +void +sigfpe_default(int signo) +{ + static struct proc *td; + + td = this_td(); + kprintf("Floating point exception (pid=%d)\n", td->pid); + exit1(td); +} + +void +sigkill_default(int signo) +{ + static struct proc *td; + + td = this_td(); + kprintf("Terminated (pid=%d)\n", td->pid); + exit1(td); +} + +void +sigsegv_default(int signo) +{ + static struct proc *td; + + td = this_td(); + kprintf("Segmentation fault (pid=%d)\n", td->pid); + exit1(td); +} int dev_noread(void) -- cgit v1.2.3