do_kill distinguish PTRACE_CONT from kill.

This commit is contained in:
Tomoki Shirasawa
2014-12-26 15:23:11 +09:00
parent e25d35a191
commit 912b8a886c
4 changed files with 99 additions and 103 deletions

View File

@@ -158,7 +158,7 @@ SYSCALL_DECLARE(rt_sigreturn)
} }
extern struct cpu_local_var *clv; 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 void interrupt_syscall(int all, int pid);
extern int num_processors; extern int num_processors;
@@ -277,6 +277,46 @@ peekuser(struct process *proc, void *regs0)
extern void coredump(struct process *proc, void *regs); 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 void
do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pending *pending) 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; __sigset_t w;
int irqstate; int irqstate;
struct fork_tree_node *ftn = proc->ftn; struct fork_tree_node *ftn = proc->ftn;
int orgsig;
int ptraceflag = 0;
for(w = pending->sigmask.__val[0], sig = 0; w; sig++, w >>= 1); for(w = pending->sigmask.__val[0], sig = 0; w; sig++, w >>= 1);
dkprintf("do_signal,pid=%d,sig=%d\n", proc->ftn->pid, sig); 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 */ if(regs == NULL){ /* call from syscall */
asm("movq %%gs:132, %0" : "=r" (regs)); 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 SIGTSTP:
case SIGTTIN: case SIGTTIN:
case SIGTTOU: 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 */ /* Update process state in fork tree */
ihk_mc_spinlock_lock_noirq(&ftn->lock); ihk_mc_spinlock_lock_noirq(&ftn->lock);
ftn->group_exit_status = SIGSTOP; ftn->group_exit_status = SIGSTOP;
/* Reap and set new signal_flags */ /* Reap and set new signal_flags */
ftn->signal_flags = SIGNAL_STOP_STOPPED; ftn->signal_flags = SIGNAL_STOP_STOPPED;
ftn->status = PS_STOPPED; ftn->status = PS_STOPPED;
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock); ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
/* Wake up the parent who tried wait4 and sleeping */ /* Wake up the parent who tried wait4 and sleeping */
waitq_wakeup(&proc->ftn->parent->waitpid_q); waitq_wakeup(&proc->ftn->parent->waitpid_q);
dkprintf("do_signal,SIGSTOP,sleeping\n"); dkprintf("do_signal,SIGSTOP,sleeping\n");
/* Sleep */ /* Sleep */
proc->ftn->status = PS_STOPPED; proc->ftn->status = PS_STOPPED;
schedule(); schedule();
dkprintf("SIGSTOP(): woken up\n"); dkprintf("SIGSTOP(): woken up\n");
}
break; break;
case SIGTRAP: case SIGTRAP:
dkprintf("do_signal,SIGTRAP\n"); dkprintf("do_signal,SIGTRAP\n");
@@ -419,71 +474,17 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin
coredumped = 0x80; coredumped = 0x80;
terminate(0, sig | coredumped, (ihk_mc_user_context_t *)regs->rsp); terminate(0, sig | coredumped, (ihk_mc_user_context_t *)regs->rsp);
break; break;
case SIGHUP: case SIGCHLD:
case SIGINT: case SIGURG:
case SIGKILL: break;
case SIGPIPE: default:
case SIGALRM:
case SIGTERM:
case SIGUSR1:
case SIGUSR2:
dkprintf("do_signal,default,terminate,sig=%d\n", sig); dkprintf("do_signal,default,terminate,sig=%d\n", sig);
terminate(0, sig, (ihk_mc_user_context_t *)regs->rsp); terminate(0, sig, (ihk_mc_user_context_t *)regs->rsp);
break; 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 void
check_signal(unsigned long rc, void *regs0) check_signal(unsigned long rc, void *regs0)
{ {
@@ -493,9 +494,8 @@ check_signal(unsigned long rc, void *regs0)
struct sig_pending *next; struct sig_pending *next;
struct list_head *head; struct list_head *head;
ihk_spinlock_t *lock; ihk_spinlock_t *lock;
__sigset_t w, sig_bv;
int irqstate; int irqstate;
int sig; __sigset_t w;
if(clv == NULL) if(clv == NULL)
return; return;
@@ -542,18 +542,12 @@ check_signal(unsigned long rc, void *regs0)
return; 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); do_signal(rc, regs, proc, pending);
} }
} }
unsigned long 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); dkprintf("do_kill,pid=%d,tid=%d,sig=%d\n", pid, tid, sig);
struct cpu_local_var *v; 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); ihk_mc_spinlock_unlock(&(v->runq_lock), irqstate);
} }
for(i = 0; i < n; i++) 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) if(sendme)
rc = do_kill(proc->ftn->pid, -1, sig, info); rc = do_kill(proc->ftn->pid, -1, sig, info, ptracecont);
kfree(pids); kfree(pids);
return rc; return rc;
@@ -733,11 +727,13 @@ do_kill(int pid, int tid, int sig, siginfo_t *info)
k = tproc->sighandler->action + sig - 1; k = tproc->sighandler->action + sig - 1;
if(k->sa.sa_handler != (void *)1 && if(k->sa.sa_handler != (void *)1 &&
(k->sa.sa_handler != NULL || (k->sa.sa_handler != NULL ||
(tproc->ftn->ptrace & PT_TRACED) ||
(sig != SIGCHLD && sig != SIGURG))){ (sig != SIGCHLD && sig != SIGURG))){
struct sig_pending *pending = NULL; struct sig_pending *pending = NULL;
if (sig < 33) { // SIGRTMIN - SIGRTMAX if (sig < 33) { // SIGRTMIN - SIGRTMAX
list_for_each_entry(pending, head, list){ list_for_each_entry(pending, head, list){
if(pending->sigmask.__val[0] == mask) if(pending->sigmask.__val[0] == mask &&
pending->ptracecont == ptracecont)
break; break;
} }
if(&pending->list == head) if(&pending->list == head)
@@ -752,6 +748,7 @@ do_kill(int pid, int tid, int sig, siginfo_t *info)
else{ else{
pending->sigmask.__val[0] = mask; pending->sigmask.__val[0] = mask;
memcpy(&pending->info, info, sizeof(siginfo_t)); memcpy(&pending->info, info, sizeof(siginfo_t));
pending->ptracecont = ptracecont;
if(sig == SIGKILL || sig == SIGSTOP) if(sig == SIGKILL || sig == SIGSTOP)
list_add(&pending->list, head); list_add(&pending->list, head);
else else
@@ -785,15 +782,13 @@ do_kill(int pid, int tid, int sig, siginfo_t *info)
interrupt_syscall(pid, cpuid); interrupt_syscall(pid, cpuid);
if (status != PS_RUNNING) { if (status != PS_RUNNING) {
switch(sig) { if(sig == SIGKILL){
case SIGKILL:
/* Wake up the target only when stopped by ptrace-reporting */ /* Wake up the target only when stopped by ptrace-reporting */
sched_wakeup_process(tproc, PS_TRACED | PS_STOPPED); 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 */ /* Wake up the target only when stopped by SIGSTOP */
sched_wakeup_process(tproc, PS_STOPPED); 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); terminate(0, sig | 0x80, (ihk_mc_user_context_t *)regs->rsp);
} }
else else
do_kill(proc->ftn->pid, proc->ftn->tid, sig, info); do_kill(proc->ftn->pid, proc->ftn->tid, sig, info, 0);
} }

View File

@@ -468,7 +468,7 @@ static void syscall_channel_send(struct ihk_ikc_channel_desc *c,
ihk_ikc_send(c, packet, 0); 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 settid(struct process *proc, int mode, int newcpuid, int oldcpuid);
extern void process_procfs_request(unsigned long rarg); 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; pckt.arg = packet->arg;
syscall_channel_send(c, &pckt); 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); kprintf("SCD_MSG_SEND_SIGNAL: do_kill(pid=%d, tid=%d, sig=%d)=%d\n", info.pid, info.tid, info.sig, rc);
return 0; return 0;
case SCD_MSG_PROCFS_REQUEST: case SCD_MSG_PROCFS_REQUEST:

View File

@@ -243,6 +243,7 @@ struct sig_pending {
struct list_head list; struct list_head list;
sigset_t sigmask; sigset_t sigmask;
siginfo_t info; siginfo_t info;
int ptracecont;
}; };
struct sig_shared { struct sig_shared {

View File

@@ -95,7 +95,7 @@ static char *syscall_name[] MCKERNEL_UNUSED = {
void check_signal(unsigned long rc, void *regs); void check_signal(unsigned long rc, void *regs);
void do_signal(long rc, void *regs, struct process *proc, struct sig_pending *pending); 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_from_user(struct process *, void *, const void *, size_t);
int copy_to_user(struct process *, void *, const void *, size_t); int copy_to_user(struct process *, void *, const void *, size_t);
void do_setpgid(int, int); 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); info._sifields._sigchld.si_status = ((rc & 0x00ff) << 8) | (sig & 0xff);
dkprintf("terminate,kill %d,target pid=%d\n", dkprintf("terminate,kill %d,target pid=%d\n",
ftn->termsig, parent_owner_pid); 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); sigchld_parent(ftn->parent->owner, 0);
*/ */
@@ -648,7 +648,7 @@ void terminate_host(int pid)
ihk_mc_spinlock_unlock(&(v->runq_lock), irqstate); ihk_mc_spinlock_unlock(&(v->runq_lock), irqstate);
} }
for(i = 0; i < n; i++){ for(i = 0; i < n; i++){
do_kill(pid, tids[i], SIGKILL, &info); do_kill(pid, tids[i], SIGKILL, &info, 0);
} }
kfree(tids); kfree(tids);
@@ -1453,7 +1453,7 @@ static int ptrace_report_exec(struct process *proc)
info.si_code = CLD_TRAPPED; info.si_code = CLD_TRAPPED;
info._sifields._sigchld.si_pid = proc->ftn->pid; info._sifields._sigchld.si_pid = proc->ftn->pid;
info._sifields._sigchld.si_status = proc->ftn->exit_status; 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) { if(rc < 0) {
dkprintf("ptrace_report_exec,do_kill failed\n"); dkprintf("ptrace_report_exec,do_kill failed\n");
} }
@@ -1781,7 +1781,7 @@ SYSCALL_DECLARE(kill)
info._sifields._kill.si_pid = proc->ftn->pid; info._sifields._kill.si_pid = proc->ftn->pid;
dkprintf("sys_kill,enter,pid=%d,sig=%d\n", pid, sig); 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); dkprintf("sys_kill,returning,pid=%d,sig=%d,error=%d\n", pid, sig, error);
return error; return error;
} }
@@ -1805,7 +1805,7 @@ SYSCALL_DECLARE(tgkill)
if(tgid <= 0 && tgid != -1) if(tgid <= 0 && tgid != -1)
return -EINVAL; return -EINVAL;
return do_kill(tgid, tid, sig, &info); return do_kill(tgid, tid, sig, &info, 0);
} }
SYSCALL_DECLARE(setpgid) SYSCALL_DECLARE(setpgid)
@@ -1998,7 +1998,7 @@ SYSCALL_DECLARE(rt_sigqueueinfo)
if(copy_from_user(proc, &info, winfo, sizeof info)) if(copy_from_user(proc, &info, winfo, sizeof info))
return -EFAULT; return -EFAULT;
return do_kill(pid, -1, sig, &info); return do_kill(pid, -1, sig, &info, 0);
} }
static int static int
@@ -2408,7 +2408,7 @@ static int ptrace_wakeup_sig(int pid, long request, long data) {
case PTRACE_KILL: case PTRACE_KILL:
memset(&info, '\0', sizeof info); memset(&info, '\0', sizeof info);
info.si_signo = SIGKILL; info.si_signo = SIGKILL;
error = do_kill(pid, -1, SIGKILL, &info); error = do_kill(pid, -1, SIGKILL, &info, 0);
if (error < 0) { if (error < 0) {
goto out; goto out;
} }
@@ -2424,7 +2424,7 @@ static int ptrace_wakeup_sig(int pid, long request, long data) {
info.si_signo = data; info.si_signo = data;
info.si_code = SI_USER; info.si_code = SI_USER;
info._sifields._kill.si_pid = proc->ftn->pid; 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) { if (error < 0) {
goto out; goto out;
} }