X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/0cf90cca0c924622f3fee8d2a3fafa8238363dc6..6f6da1abb22dff69dbb710bd2fd9d95f083f2b43:/lunaix-os/kernel/process/signal.c diff --git a/lunaix-os/kernel/process/signal.c b/lunaix-os/kernel/process/signal.c index 0f43b1f..c4e1662 100644 --- a/lunaix-os/kernel/process/signal.c +++ b/lunaix-os/kernel/process/signal.c @@ -4,97 +4,94 @@ #include #include #include +#include #include +#include + +LOG_MODULE("SIG") + extern struct scheduler sched_ctx; /* kernel/sched.c */ -void __USER__ -default_sighandler_term(int signum) +#define UNMASKABLE (sigset(SIGKILL) | sigset(SIGTERM)) +#define TERMSIG (sigset(SIGSEGV) | sigset(SIGINT) | UNMASKABLE) +#define CORE (sigset(SIGSEGV)) +#define within_kstack(addr) \ + (KERNEL_STACK <= (addr) && (addr) <= KERNEL_STACK_END) + +static inline void +signal_terminate(int errcode) { - _exit(signum); + terminate_proc(errcode | PEXITSIG); } -void* default_handlers[_SIG_NUM] = { - // TODO: 添加默认handler - [_SIGINT] = default_sighandler_term, [_SIGTERM] = default_sighandler_term, - [_SIGKILL] = default_sighandler_term, [_SIGSEGV] = default_sighandler_term, - [_SIGINT] = default_sighandler_term, -}; - -volatile struct proc_sigstate __temp_save; // Referenced in kernel/asm/x86/interrupt.S void* signal_dispatch() { - if (!__current->sig_pending) { + if (!__current->sigctx.sig_pending) { // 没有待处理信号 return 0; } - int sig_selected = - 31 - __builtin_clz(__current->sig_pending & - ~(__current->sig_mask | __current->sig_inprogress)); + struct sighail* psig = &__current->sigctx; + struct sigact* prev_working = psig->inprogress; + sigset_t mask = psig->sig_mask | (prev_working ? prev_working->sa_mask : 0); - __SIGCLEAR(__current->sig_pending, sig_selected); + int sig_selected = 31 - __builtin_clz(psig->sig_pending & ~mask); + + sigset_clear(psig->sig_pending, sig_selected); + + struct sigact* action = &psig->signals[sig_selected]; if (sig_selected == 0) { // SIG0 is reserved return 0; } - if (!__current->sig_handler[sig_selected] && - !default_handlers[sig_selected]) { - // 如果该信号没有handler,则忽略 + if (!action->sa_actor) { + if (sigset_test(TERMSIG, sig_selected)) { + signal_terminate(sig_selected); + schedule(); + // never return + } return 0; } - uintptr_t ustack = __current->ustack_top & ~0xf; + ptr_t ustack = __current->ustack_top; - if ((int)(ustack - USTACK_END) < (int)sizeof(struct proc_sig)) { + if ((int)(ustack - USR_STACK) < (int)sizeof(struct proc_sig)) { // 用户栈没有空间存放信号上下文 return 0; } - struct proc_sig* sig_ctx = - (struct proc_sig*)(ustack - sizeof(struct proc_sig)); + struct proc_sig* sigframe = + (struct proc_sig*)((ustack - sizeof(struct proc_sig)) & ~0xf); - /* - 这是一个相当恶心的坑。 - 问题是出在原本的sig_ctx->prev_context = __current->intr_ctx的上面 - 这个语句会被gcc在编译时,用更加高效的 rep movsl 来代替。 + sigframe->sig_num = sig_selected; + sigframe->sigact = action->sa_actor; + sigframe->sighand = action->sa_handler; - 由于我们采用按需分页,所以在很多情况下,用户栈实际被分配的空间不允许我们进行完整的 - 注入,而需要走page fault handler进行动态分页。 + sigframe->saved_ictx = __current->intr_ctx; - 竞态条件就出现在这里! + action->prev = prev_working; + psig->inprogress = action; - 假若我们的__current->intr_ctx注入了一半,然后产生page-fault中断, - 那么这就会导致我们的__current->intr_ctx被这个page-fault中断导致的 - 上下文信息覆盖。那么当page-fault handler成功分配了一个页,返回, - 拷贝也就得以进行。遗憾的是,只不过这次拷贝的内容和前面的拷贝是没有任何的关系 - (因为此时的intr_ctx已经不是之前的intr_ctx了!) - 而这就会导致我们保存在信号上下文中的进程上下文信息不完整,从而在soft_iret时 - 触发#GP。 - - 解决办法就是先吧intr_ctx拷贝到一个静态分配的区域里,然后再注入到用户栈。 - */ - __temp_save.proc_regs = __current->intr_ctx; - memcpy(__temp_save.fxstate, __current->fxstate, 512); - - sig_ctx->prev_context = __temp_save; - - sig_ctx->sig_num = sig_selected; - sig_ctx->signal_handler = __current->sig_handler[sig_selected]; - - if (!sig_ctx->signal_handler) { - // 如果没有用户自定义的Handler,则使用系统默认Handler。 - sig_ctx->signal_handler = default_handlers[sig_selected]; - } + return sigframe; +} - __SIGSET(__current->sig_inprogress, sig_selected); +void +proc_clear_signal(struct proc_info* proc) +{ + memset(&proc->sigctx, 0, sizeof(proc->sigctx)); +} - return sig_ctx; +void +proc_setsignal(struct proc_info* proc, int signum) +{ + sigset_add(proc->sigctx.sig_pending, signum); + proc->sigctx.signals[signum].sender = __current->pid; } int @@ -105,7 +102,9 @@ signal_send(pid_t pid, int signum) return -1; } + pid_t sender_pid = __current->pid; struct proc_info* proc; + if (pid > 0) { proc = get_process(pid); goto send_single; @@ -126,25 +125,57 @@ send_grp: struct proc_info *pos, *n; llist_for_each(pos, n, &proc->grp_member, grp_member) { - __SIGSET(pos->sig_pending, signum); + struct sighail* sh = &pos->sigctx; + sigset_add(sh->sig_pending, signum); + sh->signals[signum].sender = sender_pid; } send_single: - if (PROC_TERMINATED(proc->state)) { + if (proc_terminated(proc)) { __current->k_status = EINVAL; return -1; } - __SIGSET(proc->sig_pending, signum); + + sigset_add(proc->sigctx.sig_pending, signum); + proc->sigctx.signals[signum].sender = sender_pid; + return 0; } __DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx) { - memcpy(__current->fxstate, sig_ctx->prev_context.fxstate, 512); - __current->intr_ctx = sig_ctx->prev_context.proc_regs; - __current->flags &= ~PROC_FINPAUSE; - __SIGCLEAR(__current->sig_inprogress, sig_ctx->sig_num); + __current->intr_ctx = sig_ctx->saved_ictx; + + struct sigact* current = __current->sigctx.inprogress; + if (current) { + __current->sigctx.inprogress = current->prev; + current->prev = NULL; + } else { + __current->sigctx.inprogress = NULL; + } + + if (proc_terminated(__current)) { + __current->exit_code |= PEXITSIG; + } else if (sigset_test(CORE, sig_ctx->sig_num)) { + signal_terminate(sig_ctx->sig_num); + } + + ptr_t ictx = (ptr_t)__current->intr_ctx; + + /* + Ensure our restored context is within kernel stack + + This prevent user to forge their own context such that arbitrary code + can be executed as supervisor level + */ + if (!within_kstack(ictx)) { + signal_terminate(SIGSEGV); + } + schedule(); + + // never reach! + return 0; } __DEFINE_LXSYSCALL3(int, @@ -156,50 +187,48 @@ __DEFINE_LXSYSCALL3(int, sigset_t, *oldset) { - *oldset = __current->sig_mask; + struct sighail* sh = &__current->sigctx; + *oldset = sh->sig_mask; + if (how == _SIG_BLOCK) { - __current->sig_mask |= *set; + sigset_union(sh->sig_mask, *set); } else if (how == _SIG_UNBLOCK) { - __current->sig_mask &= ~(*set); + sigset_intersect(sh->sig_mask, ~(*set)); } else if (how == _SIG_SETMASK) { - __current->sig_mask = *set; + sh->sig_mask = *set; } else { return 0; } - __current->sig_mask &= ~_SIGNAL_UNMASKABLE; + + sigset_intersect(sh->sig_mask, ~UNMASKABLE); return 1; } -__DEFINE_LXSYSCALL2(int, signal, int, signum, sighandler_t, handler) +__DEFINE_LXSYSCALL2(int, sys_sigaction, int, signum, struct sigaction*, action) { if (signum <= 0 || signum >= _SIG_NUM) { return -1; } - if ((__SIGNAL(signum) & _SIGNAL_UNMASKABLE)) { + if (sigset_test(UNMASKABLE, signum)) { return -1; } - __current->sig_handler[signum] = (void*)handler; + struct sigact* sa = &__current->sigctx.signals[signum]; + + sa->sa_actor = (void*)action->sa_sigaction; + sa->sa_handler = (void*)action->sa_handler; + sigset_union(sa->sa_mask, sigset(signum)); return 0; } -void -__do_pause() +__DEFINE_LXSYSCALL(int, pause) { - __current->flags |= PROC_FINPAUSE; - - while ((__current->flags & PROC_FINPAUSE)) { - sched_yieldk(); - } + pause_current(); + sched_yieldk(); __current->k_status = EINTR; -} - -__DEFINE_LXSYSCALL(int, pause) -{ - __do_pause(); return -1; } @@ -210,15 +239,18 @@ __DEFINE_LXSYSCALL2(int, kill, pid_t, pid, int, signum) __DEFINE_LXSYSCALL1(int, sigpending, sigset_t, *sigset) { - *sigset = __current->sig_pending; + *sigset = __current->sigctx.sig_pending; return 0; } __DEFINE_LXSYSCALL1(int, sigsuspend, sigset_t, *mask) { - sigset_t tmp = __current->sig_mask; - __current->sig_mask = (*mask) & ~_SIGNAL_UNMASKABLE; - __do_pause(); - __current->sig_mask = tmp; + sigset_t tmp = __current->sigctx.sig_mask; + __current->sigctx.sig_mask = (*mask) & ~UNMASKABLE; + + pause_current(); + sched_yieldk(); + + __current->sigctx.sig_mask = tmp; return -1; } \ No newline at end of file