From ae689abff5cf8ec3308d57ebf1b8867ea4af29eb Mon Sep 17 00:00:00 2001 From: Theodore Dubois Date: Sat, 22 Jun 2019 19:48:39 -0700 Subject: [PATCH] Require a siginfo when sending a signal --- fs/tty.c | 4 ++-- kernel/calls.c | 14 +++++++++++--- kernel/errno.c | 2 +- kernel/exit.c | 14 ++++++++++++-- kernel/signal.c | 22 +++++++++++++++------- kernel/signal.h | 48 +++++++++++++++++++++++++++++++++++++++++++++--- kernel/time.c | 9 ++++++--- kernel/time.h | 12 ++++++++---- misc.h | 1 + 9 files changed, 101 insertions(+), 25 deletions(-) diff --git a/fs/tty.c b/fs/tty.c index c159bf00..e587d632 100644 --- a/fs/tty.c +++ b/fs/tty.c @@ -345,7 +345,7 @@ canon_wake: if (fg_group != 0) { for (int sig = 0; sig < NUM_SIGS; sig++) { if (queue & (1l << sig)) - send_group_signal(fg_group, sig); + send_group_signal(fg_group, sig, SIGINFO_NIL); } } @@ -732,7 +732,7 @@ static int tty_ioctl(struct fd *fd, int cmd, void *arg) { void tty_set_winsize(struct tty *tty, struct winsize_ winsize) { tty->winsize = winsize; if (tty->fg_group != 0) - send_group_signal(tty->fg_group, SIGWINCH_); + send_group_signal(tty->fg_group, SIGWINCH_, SIGINFO_NIL); } void tty_hangup(struct tty *tty) { diff --git a/kernel/calls.c b/kernel/calls.c index d1246c0a..137970b8 100644 --- a/kernel/calls.c +++ b/kernel/calls.c @@ -211,7 +211,7 @@ void handle_interrupt(int interrupt) { unsigned syscall_num = cpu->eax; if (syscall_num >= NUM_SYSCALLS || syscall_table[syscall_num] == NULL) { printk("%d missing syscall %d\n", current->pid, syscall_num); - send_signal(current, SIGSYS_); + deliver_signal(current, SIGSYS_, SIGINFO_NIL); } else { STRACE("%d call %-3d ", current->pid, syscall_num); int result = syscall_table[syscall_num](cpu->ebx, cpu->ecx, cpu->edx, cpu->esi, cpu->edi, cpu->ebp); @@ -220,7 +220,11 @@ void handle_interrupt(int interrupt) { } } else if (interrupt == INT_GPF) { printk("%d page fault on 0x%x at 0x%x\n", current->pid, cpu->segfault_addr, cpu->eip); - deliver_signal(current, SIGSEGV_); + struct siginfo_ info = { + .code = SI_KERNEL_, + .fault.addr = cpu->segfault_addr, + }; + deliver_signal(current, SIGSEGV_, info); } else if (interrupt == INT_UNDEFINED) { printk("%d illegal instruction at 0x%x: ", current->pid, cpu->eip); for (int i = 0; i < 8; i++) { @@ -230,7 +234,11 @@ void handle_interrupt(int interrupt) { printk("%02x ", b); } printk("\n"); - deliver_signal(current, SIGILL_); + struct siginfo_ info = { + .code = SI_KERNEL_, + .fault.addr = cpu->eip, + }; + deliver_signal(current, SIGILL_, info); } else if (interrupt != INT_TIMER) { printk("%d unhandled interrupt %d\n", current->pid, interrupt); sys_exit(interrupt); diff --git a/kernel/errno.c b/kernel/errno.c index 58d619c8..49b4a69e 100644 --- a/kernel/errno.c +++ b/kernel/errno.c @@ -97,6 +97,6 @@ int err_map(int err) { int errno_map() { if (errno == EPIPE) - send_signal(current, SIGPIPE_); + send_signal(current, SIGPIPE_, SIGINFO_NIL); return err_map(errno); } diff --git a/kernel/exit.c b/kernel/exit.c index 6f4580c5..9dc1449b 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -56,6 +56,7 @@ noreturn void do_exit(int status) { struct rusage_ rusage = rusage_get_current(); lock(¤t->group->lock); rusage_add(¤t->group->rusage, &rusage); + struct rusage_ group_rusage = current->group->rusage; unlock(¤t->group->lock); // the actual freeing needs pids_lock @@ -83,7 +84,16 @@ noreturn void do_exit(int status) { } else { leader->zombie = true; notify(&parent->group->child_exit); - send_signal(parent, leader->exit_signal); + struct siginfo_ info = { + .code = SI_KERNEL_, + .child.pid = current->pid, + .child.uid = current->uid, + .child.status = current->exit_code, + .child.utime = clock_from_timeval(group_rusage.utime), + .child.stime = clock_from_timeval(group_rusage.stime), + }; + if (leader->exit_signal != 0) + send_signal(parent, leader->exit_signal, info); } if (exit_hook != NULL) @@ -111,7 +121,7 @@ noreturn void do_exit_group(int status) { // kill everyone else in the group struct task *task; list_for_each_entry(&group->threads, task, group_links) { - deliver_signal(task, SIGKILL_); + deliver_signal(task, SIGKILL_, SIGINFO_NIL); task->group->stopped = false; notify(&task->group->stopped_cond); } diff --git a/kernel/signal.c b/kernel/signal.c index 7ec82716..c253d8fe 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -65,13 +65,13 @@ retry: } } -void deliver_signal(struct task *task, int sig) { +void deliver_signal(struct task *task, int sig, struct siginfo_ UNUSED(info)) { lock(&task->sighand->lock); deliver_signal_unlocked(task, sig); unlock(&task->sighand->lock); } -void send_signal(struct task *task, int sig) { +void send_signal(struct task *task, int sig, struct siginfo_ UNUSED(info)) { // signal zero is for testing whether a process exists if (sig == 0) return; @@ -97,6 +97,8 @@ void send_signal(struct task *task, int sig) { } bool try_self_signal(int sig) { + assert(sig == SIGTTIN_ || sig == SIGTTOU_); + struct sighand *sighand = current->sighand; lock(&sighand->lock); bool can_send = signal_action(sighand, sig) != SIGNAL_IGNORE && @@ -107,7 +109,7 @@ bool try_self_signal(int sig) { return can_send; } -int send_group_signal(dword_t pgid, int sig) { +int send_group_signal(dword_t pgid, int sig, struct siginfo_ info) { lock(&pids_lock); struct pid *pid = pid_get(pgid); if (pid == NULL) { @@ -116,7 +118,7 @@ int send_group_signal(dword_t pgid, int sig) { } struct tgroup *tgroup; list_for_each_entry(&pid->pgroup, tgroup, pgroup) { - send_signal(tgroup->leader, sig); + send_signal(tgroup->leader, sig, info); } unlock(&pids_lock); return 0; @@ -227,7 +229,8 @@ bool receive_signals() { if (now_stopped) { lock(&pids_lock); notify(¤t->parent->group->child_exit); - send_signal(current->parent, current->group->leader->exit_signal); + // TODO add siginfo + send_signal(current->parent, current->group->leader->exit_signal, SIGINFO_NIL); unlock(&pids_lock); } } @@ -462,11 +465,16 @@ int do_kill(pid_t_ pid, dword_t sig, pid_t_ tgid) { STRACE("kill(%d, %d)", pid, sig); if (sig >= NUM_SIGS) return _EINVAL; + struct siginfo_ info = { + .code = SI_USER_, + .kill.pid = current->pid, + .kill.uid = current->uid, + }; // TODO check permissions if (pid == 0) pid = -current->group->pgid; if (pid < 0) - return send_group_signal(-pid, sig); + return send_group_signal(-pid, sig, info); lock(&pids_lock); struct task *task = pid_get_task(pid); @@ -481,7 +489,7 @@ int do_kill(pid_t_ pid, dword_t sig, pid_t_ tgid) { return _ESRCH; } - send_signal(task, sig); + send_signal(task, sig, info); unlock(&pids_lock); return 0; } diff --git a/kernel/signal.h b/kernel/signal.h index 6c2408c4..b9430b4e 100644 --- a/kernel/signal.h +++ b/kernel/signal.h @@ -51,16 +51,58 @@ struct sigaction_ { #define SIGPWR_ 30 #define SIGSYS_ 31 +#define SI_USER_ 0 +#define SI_TIMER_ -2 +#define SI_TKILL_ -6 +#define SI_KERNEL_ 128 + +union sigval_ { + int_t sv_int; + addr_t sv_ptr; +}; + +struct siginfo_ { + int_t signo; + int_t code; + int_t sig_errno; + union { + struct { + pid_t_ pid; + uid_t_ uid; + } kill; + struct { + pid_t_ pid; + uid_t_ uid; + int_t status; + clock_t_ utime; + clock_t_ stime; + } child; + struct { + addr_t addr; + } fault; + struct { + addr_t addr; + int_t syscall; + } sigsys; + char __pad[128 - 3 * sizeof(int_t)]; + }; +}; + +// a reasonable default siginfo +static const struct siginfo_ SIGINFO_NIL = { + .code = SI_KERNEL_, +}; + // send a signal // you better make sure the task isn't gonna get freed under me (pids_lock or current) -void send_signal(struct task *task, int sig); +void send_signal(struct task *task, int sig, struct siginfo_ info); // send a signal without regard for whether the signal is blocked or ignored -void deliver_signal(struct task *task, int sig); +void deliver_signal(struct task *task, int sig, struct siginfo_ info); // send a signal to current if it's not blocked or ignored, return whether that worked // exists specifically for sending SIGTTIN/SIGTTOU bool try_self_signal(int sig); // send a signal to all processes in a group, could return ESRCH -int send_group_signal(dword_t pgid, int sig); +int send_group_signal(dword_t pgid, int sig, struct siginfo_ info); // check for and deliver pending signals on current // returns whether signals were received // must be called without pids_lock diff --git a/kernel/time.c b/kernel/time.c index 13731ab9..394d7771 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -77,7 +77,10 @@ dword_t sys_clock_settime(dword_t UNUSED(clock), addr_t UNUSED(tp)) { } static void itimer_notify(struct task *task) { - send_signal(task, SIGALRM_); + struct siginfo_ info = { + .code = SI_TIMER_, + }; + send_signal(task, SIGALRM_, info); } static int itimer_set(struct tgroup *group, int which, struct timer_spec spec, struct timer_spec *old_spec) { @@ -179,8 +182,8 @@ dword_t sys_times(addr_t tbuf) { if (tbuf) { struct tms_ tmp; struct rusage_ rusage = rusage_get_current(); - tmp.tms_utime = (rusage.utime.sec * 100) + (rusage.utime.usec/10000); - tmp.tms_stime = (rusage.utime.sec * 100) + (rusage.utime.usec/10000); + tmp.tms_utime = clock_from_timeval(rusage.utime); + tmp.tms_stime = clock_from_timeval(rusage.stime); tmp.tms_cutime = tmp.tms_utime; tmp.tms_cstime = tmp.tms_stime; if (user_put(tbuf, tmp)) diff --git a/kernel/time.h b/kernel/time.h index 99be04ba..79f89b4d 100644 --- a/kernel/time.h +++ b/kernel/time.h @@ -24,6 +24,10 @@ struct timezone_ { dword_t dsttime; }; +static inline clock_t_ clock_from_timeval(struct timeval_ timeval) { + return timeval.sec * 100 + timeval.usec / 10000; +} + #define ITIMER_REAL_ 0 #define ITIMER_VIRTUAL_ 1 #define ITIMER_PROF_ 2 @@ -33,10 +37,10 @@ struct itimerval_ { }; struct tms_ { - dword_t tms_utime; /* user time */ - dword_t tms_stime; /* system time */ - dword_t tms_cutime; /* user time of children */ - dword_t tms_cstime; /* system time of children */ + clock_t_ tms_utime; /* user time */ + clock_t_ tms_stime; /* system time */ + clock_t_ tms_cutime; /* user time of children */ + clock_t_ tms_cstime; /* system time of children */ }; int_t sys_setitimer(int_t which, addr_t new_val, addr_t old_val); diff --git a/misc.h b/misc.h index dd3e22ef..5283811b 100644 --- a/misc.h +++ b/misc.h @@ -67,6 +67,7 @@ typedef sdword_t pid_t_; typedef dword_t uid_t_; typedef word_t mode_t_; typedef sqword_t off_t_; +typedef dword_t clock_t_; #define uint(size) glue3(uint,size,_t) #define sint(size) glue3(int,size,_t)