From 912b8a886c7216de994e1ecfd7519262cd9b50f3 Mon Sep 17 00:00:00 2001 From: Tomoki Shirasawa Date: Fri, 26 Dec 2014 15:23:11 +0900 Subject: [PATCH] do_kill distinguish PTRACE_CONT from kill. --- arch/x86/kernel/syscall.c | 179 ++++++++++++++++++-------------------- kernel/host.c | 4 +- kernel/include/process.h | 1 + kernel/syscall.c | 18 ++-- 4 files changed, 99 insertions(+), 103 deletions(-) diff --git a/arch/x86/kernel/syscall.c b/arch/x86/kernel/syscall.c index b6e4b82a..08c075df 100644 --- a/arch/x86/kernel/syscall.c +++ b/arch/x86/kernel/syscall.c @@ -158,7 +158,7 @@ SYSCALL_DECLARE(rt_sigreturn) } extern struct cpu_local_var *clv; -extern unsigned long do_kill(int pid, int tid, int sig, struct siginfo *info); +extern unsigned long do_kill(int pid, int tid, int sig, struct siginfo *info, int ptracecont); extern void interrupt_syscall(int all, int pid); extern int num_processors; @@ -277,6 +277,46 @@ peekuser(struct process *proc, void *regs0) extern void coredump(struct process *proc, void *regs); +static void ptrace_report_signal(struct process *proc, struct x86_regs *regs, int sig) +{ + long rc; + + dkprintf("ptrace_report_signal,pid=%d\n", proc->ftn->pid); + + peekuser(proc, regs); + ihk_mc_spinlock_lock_noirq(&proc->ftn->lock); + proc->ftn->exit_status = sig; + /* Transition process state */ + proc->ftn->status = PS_TRACED; + ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock); + if (proc->ftn->parent) { + /* kill SIGCHLD */ + ihk_mc_spinlock_lock_noirq(&proc->ftn->parent->lock); + if (proc->ftn->parent->owner) { + struct siginfo info; + + memset(&info, '\0', sizeof info); + info.si_signo = SIGCHLD; + info.si_code = CLD_TRAPPED; + info._sifields._sigchld.si_pid = proc->ftn->pid; + info._sifields._sigchld.si_status = proc->ftn->exit_status; + rc = do_kill(proc->ftn->parent->pid, -1, SIGCHLD, &info, 0); + if (rc < 0) { + kprintf("ptrace_report_signal,do_kill failed\n"); + } + } + ihk_mc_spinlock_unlock_noirq(&proc->ftn->parent->lock); + + /* Wake parent (if sleeping in wait4()) */ + waitq_wakeup(&proc->ftn->parent->waitpid_q); + } + + dkprintf("ptrace_report_signal,sleeping\n"); + /* Sleep */ + schedule(); + dkprintf("ptrace_report_signal,wake up\n"); +} + void do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pending *pending) { @@ -286,9 +326,19 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin __sigset_t w; int irqstate; struct fork_tree_node *ftn = proc->ftn; + int orgsig; + int ptraceflag = 0; for(w = pending->sigmask.__val[0], sig = 0; w; sig++, w >>= 1); dkprintf("do_signal,pid=%d,sig=%d\n", proc->ftn->pid, sig); + orgsig = sig; + + if((ftn->ptrace & PT_TRACED) && + pending->ptracecont == 0 && + sig != SIGKILL) { + ptraceflag = 1; + sig = SIGSTOP; + } if(regs == NULL){ /* call from syscall */ asm("movq %%gs:132, %0" : "=r" (regs)); @@ -361,26 +411,31 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin case SIGTSTP: case SIGTTIN: case SIGTTOU: - dkprintf("do_signal,SIGSTOP,changing state\n"); + if(ptraceflag){ + ptrace_report_signal(proc, regs, orgsig); + } + else{ + dkprintf("do_signal,SIGSTOP,changing state\n"); - /* Update process state in fork tree */ - ihk_mc_spinlock_lock_noirq(&ftn->lock); - ftn->group_exit_status = SIGSTOP; + /* Update process state in fork tree */ + ihk_mc_spinlock_lock_noirq(&ftn->lock); + ftn->group_exit_status = SIGSTOP; - /* Reap and set new signal_flags */ - ftn->signal_flags = SIGNAL_STOP_STOPPED; + /* Reap and set new signal_flags */ + ftn->signal_flags = SIGNAL_STOP_STOPPED; - ftn->status = PS_STOPPED; - ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock); + ftn->status = PS_STOPPED; + ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock); - /* Wake up the parent who tried wait4 and sleeping */ - waitq_wakeup(&proc->ftn->parent->waitpid_q); + /* Wake up the parent who tried wait4 and sleeping */ + waitq_wakeup(&proc->ftn->parent->waitpid_q); - dkprintf("do_signal,SIGSTOP,sleeping\n"); - /* Sleep */ - proc->ftn->status = PS_STOPPED; - schedule(); - dkprintf("SIGSTOP(): woken up\n"); + dkprintf("do_signal,SIGSTOP,sleeping\n"); + /* Sleep */ + proc->ftn->status = PS_STOPPED; + schedule(); + dkprintf("SIGSTOP(): woken up\n"); + } break; case SIGTRAP: dkprintf("do_signal,SIGTRAP\n"); @@ -419,71 +474,17 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin coredumped = 0x80; terminate(0, sig | coredumped, (ihk_mc_user_context_t *)regs->rsp); break; - case SIGHUP: - case SIGINT: - case SIGKILL: - case SIGPIPE: - case SIGALRM: - case SIGTERM: - case SIGUSR1: - case SIGUSR2: + case SIGCHLD: + case SIGURG: + break; + default: dkprintf("do_signal,default,terminate,sig=%d\n", sig); terminate(0, sig, (ihk_mc_user_context_t *)regs->rsp); break; - case SIGCHLD: - case SIGURG: - default: - break; } } } -static int ptrace_report_signal(struct process *proc, struct x86_regs *regs, struct sig_pending *pending) -{ - int sig; - __sigset_t w; - long rc; - - dkprintf("ptrace_report_signal,pid=%d\n", proc->ftn->pid); - - /* Save reason why stopped and process state for wait to reap */ - for (w = pending->sigmask.__val[0], sig = 0; w; sig++, w >>= 1); - ihk_mc_spinlock_lock_noirq(&proc->ftn->lock); - proc->ftn->exit_status = sig; - /* Transition process state */ - proc->ftn->status = PS_TRACED; - ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock); - if (proc->ftn->parent) { - /* kill SIGCHLD */ - ihk_mc_spinlock_lock_noirq(&proc->ftn->parent->lock); - if (proc->ftn->parent->owner) { - struct siginfo info; - - memset(&info, '\0', sizeof info); - info.si_signo = SIGCHLD; - info.si_code = CLD_TRAPPED; - info._sifields._sigchld.si_pid = proc->ftn->pid; - info._sifields._sigchld.si_status = proc->ftn->exit_status; - rc = do_kill(proc->ftn->parent->pid, -1, SIGCHLD, &info); - if (rc < 0) { - kprintf("ptrace_report_signal,do_kill failed\n"); - } - } - ihk_mc_spinlock_unlock_noirq(&proc->ftn->parent->lock); - - /* Wake parent (if sleeping in wait4()) */ - waitq_wakeup(&proc->ftn->parent->waitpid_q); - } - - peekuser(proc, regs); - dkprintf("ptrace_report_signal,sleeping\n"); - /* Sleep */ - schedule(); - dkprintf("ptrace_report_signal,wake up\n"); - - return sig; -} - void check_signal(unsigned long rc, void *regs0) { @@ -493,9 +494,8 @@ check_signal(unsigned long rc, void *regs0) struct sig_pending *next; struct list_head *head; ihk_spinlock_t *lock; - __sigset_t w, sig_bv; int irqstate; - int sig; + __sigset_t w; if(clv == NULL) return; @@ -542,18 +542,12 @@ check_signal(unsigned long rc, void *regs0) return; } - for(sig_bv = pending->sigmask.__val[0], sig = 0; sig_bv; sig++, sig_bv >>= 1); - if((proc->ftn->ptrace & PT_TRACED) && sig != SIGKILL) { - sig = ptrace_report_signal(proc, regs, pending); - /* TODO: Tracing process could overwrite signal, so handle the case here. */ - } - do_signal(rc, regs, proc, pending); } } unsigned long -do_kill(int pid, int tid, int sig, siginfo_t *info) +do_kill(int pid, int tid, int sig, siginfo_t *info, int ptracecont) { dkprintf("do_kill,pid=%d,tid=%d,sig=%d\n", pid, tid, sig); struct cpu_local_var *v; @@ -614,9 +608,9 @@ do_kill(int pid, int tid, int sig, siginfo_t *info) ihk_mc_spinlock_unlock(&(v->runq_lock), irqstate); } for(i = 0; i < n; i++) - rc = do_kill(pids[i], -1, sig, info); + rc = do_kill(pids[i], -1, sig, info, ptracecont); if(sendme) - rc = do_kill(proc->ftn->pid, -1, sig, info); + rc = do_kill(proc->ftn->pid, -1, sig, info, ptracecont); kfree(pids); return rc; @@ -733,11 +727,13 @@ do_kill(int pid, int tid, int sig, siginfo_t *info) k = tproc->sighandler->action + sig - 1; if(k->sa.sa_handler != (void *)1 && (k->sa.sa_handler != NULL || + (tproc->ftn->ptrace & PT_TRACED) || (sig != SIGCHLD && sig != SIGURG))){ struct sig_pending *pending = NULL; if (sig < 33) { // SIGRTMIN - SIGRTMAX list_for_each_entry(pending, head, list){ - if(pending->sigmask.__val[0] == mask) + if(pending->sigmask.__val[0] == mask && + pending->ptracecont == ptracecont) break; } if(&pending->list == head) @@ -752,6 +748,7 @@ do_kill(int pid, int tid, int sig, siginfo_t *info) else{ pending->sigmask.__val[0] = mask; memcpy(&pending->info, info, sizeof(siginfo_t)); + pending->ptracecont = ptracecont; if(sig == SIGKILL || sig == SIGSTOP) list_add(&pending->list, head); else @@ -785,15 +782,13 @@ do_kill(int pid, int tid, int sig, siginfo_t *info) interrupt_syscall(pid, cpuid); if (status != PS_RUNNING) { - switch(sig) { - case SIGKILL: + if(sig == SIGKILL){ /* Wake up the target only when stopped by ptrace-reporting */ sched_wakeup_process(tproc, PS_TRACED | PS_STOPPED); - break; - case SIGCONT: + } + else if(sig == SIGCONT || ptracecont){ /* Wake up the target only when stopped by SIGSTOP */ sched_wakeup_process(tproc, PS_STOPPED); - break; } } } @@ -819,5 +814,5 @@ set_signal(int sig, void *regs0, siginfo_t *info) terminate(0, sig | 0x80, (ihk_mc_user_context_t *)regs->rsp); } else - do_kill(proc->ftn->pid, proc->ftn->tid, sig, info); + do_kill(proc->ftn->pid, proc->ftn->tid, sig, info, 0); } diff --git a/kernel/host.c b/kernel/host.c index e70d1f27..05d740b3 100644 --- a/kernel/host.c +++ b/kernel/host.c @@ -468,7 +468,7 @@ static void syscall_channel_send(struct ihk_ikc_channel_desc *c, ihk_ikc_send(c, packet, 0); } -extern unsigned long do_kill(int, int, int, struct siginfo *); +extern unsigned long do_kill(int, int, int, struct siginfo *, int ptracecont); extern void settid(struct process *proc, int mode, int newcpuid, int oldcpuid); extern void process_procfs_request(unsigned long rarg); @@ -544,7 +544,7 @@ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, pckt.arg = packet->arg; syscall_channel_send(c, &pckt); - rc = do_kill(info.pid, info.tid, info.sig, &info.info); + rc = do_kill(info.pid, info.tid, info.sig, &info.info, 0); kprintf("SCD_MSG_SEND_SIGNAL: do_kill(pid=%d, tid=%d, sig=%d)=%d\n", info.pid, info.tid, info.sig, rc); return 0; case SCD_MSG_PROCFS_REQUEST: diff --git a/kernel/include/process.h b/kernel/include/process.h index 53429671..5e426597 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -243,6 +243,7 @@ struct sig_pending { struct list_head list; sigset_t sigmask; siginfo_t info; + int ptracecont; }; struct sig_shared { diff --git a/kernel/syscall.c b/kernel/syscall.c index 5ea0d5df..d0fd6e7d 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -95,7 +95,7 @@ static char *syscall_name[] MCKERNEL_UNUSED = { void check_signal(unsigned long rc, void *regs); void do_signal(long rc, void *regs, struct process *proc, struct sig_pending *pending); -extern unsigned long do_kill(int pid, int tid, int sig, struct siginfo *info); +extern unsigned long do_kill(int pid, int tid, int sig, struct siginfo *info, int ptracecont); int copy_from_user(struct process *, void *, const void *, size_t); int copy_to_user(struct process *, void *, const void *, size_t); void do_setpgid(int, int); @@ -596,7 +596,7 @@ terminate(int rc, int sig, ihk_mc_user_context_t *ctx) info._sifields._sigchld.si_status = ((rc & 0x00ff) << 8) | (sig & 0xff); dkprintf("terminate,kill %d,target pid=%d\n", ftn->termsig, parent_owner_pid); - error = do_kill(ftn->parent->pid, -1, SIGCHLD, &info); + error = do_kill(ftn->parent->pid, -1, SIGCHLD, &info, 0); /* sigchld_parent(ftn->parent->owner, 0); */ @@ -648,7 +648,7 @@ void terminate_host(int pid) ihk_mc_spinlock_unlock(&(v->runq_lock), irqstate); } for(i = 0; i < n; i++){ - do_kill(pid, tids[i], SIGKILL, &info); + do_kill(pid, tids[i], SIGKILL, &info, 0); } kfree(tids); @@ -1453,7 +1453,7 @@ static int ptrace_report_exec(struct process *proc) info.si_code = CLD_TRAPPED; info._sifields._sigchld.si_pid = proc->ftn->pid; info._sifields._sigchld.si_status = proc->ftn->exit_status; - rc = do_kill(proc->ftn->parent->pid, -1, SIGCHLD, &info); + rc = do_kill(proc->ftn->parent->pid, -1, SIGCHLD, &info, 0); if(rc < 0) { dkprintf("ptrace_report_exec,do_kill failed\n"); } @@ -1781,7 +1781,7 @@ SYSCALL_DECLARE(kill) info._sifields._kill.si_pid = proc->ftn->pid; dkprintf("sys_kill,enter,pid=%d,sig=%d\n", pid, sig); - error = do_kill(pid, -1, sig, &info); + error = do_kill(pid, -1, sig, &info, 0); dkprintf("sys_kill,returning,pid=%d,sig=%d,error=%d\n", pid, sig, error); return error; } @@ -1805,7 +1805,7 @@ SYSCALL_DECLARE(tgkill) if(tgid <= 0 && tgid != -1) return -EINVAL; - return do_kill(tgid, tid, sig, &info); + return do_kill(tgid, tid, sig, &info, 0); } SYSCALL_DECLARE(setpgid) @@ -1998,7 +1998,7 @@ SYSCALL_DECLARE(rt_sigqueueinfo) if(copy_from_user(proc, &info, winfo, sizeof info)) return -EFAULT; - return do_kill(pid, -1, sig, &info); + return do_kill(pid, -1, sig, &info, 0); } static int @@ -2408,7 +2408,7 @@ static int ptrace_wakeup_sig(int pid, long request, long data) { case PTRACE_KILL: memset(&info, '\0', sizeof info); info.si_signo = SIGKILL; - error = do_kill(pid, -1, SIGKILL, &info); + error = do_kill(pid, -1, SIGKILL, &info, 0); if (error < 0) { goto out; } @@ -2424,7 +2424,7 @@ static int ptrace_wakeup_sig(int pid, long request, long data) { info.si_signo = data; info.si_code = SI_USER; info._sifields._kill.si_pid = proc->ftn->pid; - error = do_kill(pid, -1, data, &info); + error = do_kill(pid, -1, data, &info, 1); if (error < 0) { goto out; }