-#include <lunaix/lunistd.h>
-#include <lunaix/lxsignal.h>
#include <lunaix/process.h>
#include <lunaix/sched.h>
#include <lunaix/signal.h>
#include <lunaix/spike.h>
#include <lunaix/status.h>
#include <lunaix/syscall.h>
+#include <lunaix/syslog.h>
+
+#include <klibc/string.h>
+
+#include <sys/mm/mempart.h>
+
+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 isr_param __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);
+
+ int sig_selected = 31 - clz(psig->sig_pending & ~mask);
+
+ sigset_clear(psig->sig_pending, sig_selected);
- __SIGCLEAR(__current->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 来代替。
-
- 由于我们采用按需分页,所以在很多情况下,用户栈实际被分配的空间不允许我们进行完整的
- 注入,而需要走page fault handler进行动态分页。
-
- 竞态条件就出现在这里!
+ sigframe->sig_num = sig_selected;
+ sigframe->sigact = action->sa_actor;
+ sigframe->sighand = action->sa_handler;
- 假若我们的__current->intr_ctx注入了一半,然后产生page-fault中断,
- 那么这就会导致我们的__current->intr_ctx被这个page-fault中断导致的
- 上下文信息覆盖。那么当page-fault handler成功分配了一个页,返回,
- 拷贝也就得以进行。遗憾的是,只不过这次拷贝的内容和前面的拷贝是没有任何的关系
- (因为此时的intr_ctx已经不是之前的intr_ctx了!)
- 而这就会导致我们保存在信号上下文中的进程上下文信息不完整,从而在soft_iret时
- 触发#GP。
+ sigframe->saved_ictx = __current->intr_ctx;
- 解决办法就是先吧intr_ctx拷贝到一个静态分配的区域里,然后再注入到用户栈。
- */
- __temp_save = __current->intr_ctx;
- sig_ctx->prev_context = __temp_save;
-
- sig_ctx->sig_num = sig_selected;
- sig_ctx->signal_handler = __current->sig_handler[sig_selected];
+ action->prev = prev_working;
+ psig->inprogress = action;
- 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
return -1;
}
+ pid_t sender_pid = __current->pid;
struct proc_info* proc;
+
if (pid > 0) {
proc = get_process(pid);
goto send_single;
} else if (!pid) {
proc = __current;
goto send_grp;
- } else if (pid < -1) {
+ } else if (pid < 0) {
proc = get_process(-pid);
goto send_grp;
} else {
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;
}
- return 0;
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)
{
- __current->intr_ctx = sig_ctx->prev_context;
- __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,
- sigprocmask,
- int,
- how,
- const sigset_t,
- *set,
- sigset_t,
- *oldset)
+__DEFINE_LXSYSCALL3(
+ int, sigprocmask, int, how, const sigset_t, *set, 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;
}
__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