fix PTRACE_ATTACH, PTRACE_DETACH, detach at tracer process terminated.

tracee process may have no parent, increment/decrement refcount.

refs #374
refs #280
This commit is contained in:
Susumu Komae
2015-02-25 21:09:44 +09:00
committed by postpeta
parent e91d1e5b7b
commit 026164eda4

View File

@@ -2966,26 +2966,31 @@ static int ptrace_attach(int pid)
ihk_mc_spinlock_unlock(savelock, irqstate); ihk_mc_spinlock_unlock(savelock, irqstate);
dkprintf("ptrace_attach,pid=%d,proc->ftn->parent=%p\n", proc->ftn->pid, proc->ftn->parent); dkprintf("ptrace_attach,pid=%d,proc->ftn->parent=%p\n", proc->ftn->pid, proc->ftn->parent);
if (proc->ftn->parent == NULL || proc->ftn->ptrace) { if (proc->ftn->ptrace & PT_TRACED) {
error = -EPERM; error = -EPERM;
goto out; goto out;
} }
dkprintf("ptrace_attach,parent->pid=%d\n", proc->ftn->parent->pid);
ihk_mc_spinlock_lock_noirq(&proc->ftn->lock); ihk_mc_spinlock_lock_noirq(&proc->ftn->lock);
ihk_mc_spinlock_lock_noirq(&proc->ftn->parent->lock); if (proc->ftn->parent) {
dkprintf("ptrace_attach,parent->pid=%d\n", proc->ftn->parent->pid);
list_for_each_entry_safe(child, next, &proc->ftn->parent->children, siblings_list) { ihk_mc_spinlock_lock_noirq(&proc->ftn->parent->lock);
if(child == proc->ftn) {
list_del(&child->siblings_list); list_for_each_entry_safe(child, next, &proc->ftn->parent->children, siblings_list) {
goto found; if(child == proc->ftn) {
list_del(&child->siblings_list);
goto found;
}
} }
} kprintf("ptrace_attach,not found\n");
kprintf("ptrace_attach,not found\n"); error = -EPERM;
error = -EPERM; goto out_notfound;
goto out_notfound;
found: found:
ihk_mc_spinlock_unlock_noirq(&proc->ftn->parent->lock); ihk_mc_spinlock_unlock_noirq(&proc->ftn->parent->lock);
} else {
hold_fork_tree_node(proc->ftn);
}
proc->ftn->ptrace = PT_TRACED | PT_TRACE_EXEC; proc->ftn->ptrace = PT_TRACED | PT_TRACE_EXEC;
proc->ftn->ppid_parent = proc->ftn->parent; proc->ftn->ppid_parent = proc->ftn->parent;
@@ -3044,8 +3049,7 @@ static int ptrace_detach(int pid, int data)
ihk_mc_spinlock_unlock(savelock, irqstate); ihk_mc_spinlock_unlock(savelock, irqstate);
if (!(proc->ftn->ptrace & PT_TRACED) || if (!(proc->ftn->ptrace & PT_TRACED) ||
proc->ftn->parent != cpu_local_var(current)->ftn || proc->ftn->parent != cpu_local_var(current)->ftn) {
proc->ftn->ppid_parent == NULL) {
error = -ESRCH; error = -ESRCH;
goto out; goto out;
} }
@@ -3074,9 +3078,13 @@ found:
proc->ftn->parent = proc->ftn->ppid_parent; proc->ftn->parent = proc->ftn->ppid_parent;
proc->ftn->ppid_parent = NULL; proc->ftn->ppid_parent = NULL;
ihk_mc_spinlock_lock_noirq(&proc->ftn->parent->lock); if (proc->ftn->parent) {
list_add_tail(&proc->ftn->siblings_list, &proc->ftn->parent->children); ihk_mc_spinlock_lock_noirq(&proc->ftn->parent->lock);
ihk_mc_spinlock_unlock_noirq(&proc->ftn->parent->lock); list_add_tail(&proc->ftn->siblings_list, &proc->ftn->parent->children);
ihk_mc_spinlock_unlock_noirq(&proc->ftn->parent->lock);
} else {
release_fork_tree_node(proc->ftn);
}
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock); ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
@@ -3113,8 +3121,7 @@ static int ptrace_terminate_tracer(struct process *proc, struct fork_tree_node *
dkprintf("ptrace_terminate_tracer,pid=%d\n", proc->ftn->pid); dkprintf("ptrace_terminate_tracer,pid=%d\n", proc->ftn->pid);
if (!(proc->ftn->ptrace & PT_TRACED) || if (!(proc->ftn->ptrace & PT_TRACED) ||
proc->ftn->parent != tracer || proc->ftn->parent != tracer) {
proc->ftn->ppid_parent == NULL) {
error = -ESRCH; error = -ESRCH;
goto out; goto out;
} }
@@ -3125,13 +3132,13 @@ static int ptrace_terminate_tracer(struct process *proc, struct fork_tree_node *
proc->ftn->parent = proc->ftn->ppid_parent; proc->ftn->parent = proc->ftn->ppid_parent;
proc->ftn->ppid_parent = NULL; proc->ftn->ppid_parent = NULL;
if (proc->ftn->parent == tracer) { if (proc->ftn->parent && proc->ftn->parent != tracer) {
error = 1; /* will call release_fork_tree_node() */
} else {
/* re-connect real parent */ /* re-connect real parent */
ihk_mc_spinlock_lock_noirq(&proc->ftn->parent->lock); ihk_mc_spinlock_lock_noirq(&proc->ftn->parent->lock);
list_add_tail(&proc->ftn->siblings_list, &proc->ftn->parent->children); list_add_tail(&proc->ftn->siblings_list, &proc->ftn->parent->children);
ihk_mc_spinlock_unlock_noirq(&proc->ftn->parent->lock); ihk_mc_spinlock_unlock_noirq(&proc->ftn->parent->lock);
} else {
error = 1; /* will call release_fork_tree_node() */
} }
/* if signal stopped, change to PS_STOPPED */ /* if signal stopped, change to PS_STOPPED */