ptrace: cleanup check/set of PT_PTRACED during attach
ptrace_attach() and ptrace_traceme() are the last functions which look as if the untraced task can have task->ptrace != 0, this must not be possible. Change the code to just check ->ptrace != 0 and s/|=/=/ to set PT_PTRACED. Also, a couple of trivial whitespace cleanups in ptrace_attach(). And move ptrace_traceme() up near ptrace_attach() to keep them close to each other. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Cc: Chris Wright <chrisw@sous-sol.org> Acked-by: Roland McGrath <roland@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
b79b7ba93d
commit
f2f0b00ad6
101
kernel/ptrace.c
101
kernel/ptrace.c
|
@ -177,12 +177,13 @@ int ptrace_attach(struct task_struct *task)
|
|||
if (same_thread_group(task, current))
|
||||
goto out;
|
||||
|
||||
/* Protect the target's credential calculations against our
|
||||
/*
|
||||
* Protect exec's credential calculations against our interference;
|
||||
* interference; SUID, SGID and LSM creds get determined differently
|
||||
* under ptrace.
|
||||
*/
|
||||
retval = mutex_lock_interruptible(&task->cred_guard_mutex);
|
||||
if (retval < 0)
|
||||
if (retval < 0)
|
||||
goto out;
|
||||
repeat:
|
||||
/*
|
||||
|
@ -210,10 +211,10 @@ repeat:
|
|||
retval = -EPERM;
|
||||
if (unlikely(task->exit_state))
|
||||
goto bad;
|
||||
if (task->ptrace & PT_PTRACED)
|
||||
if (task->ptrace)
|
||||
goto bad;
|
||||
|
||||
task->ptrace |= PT_PTRACED;
|
||||
task->ptrace = PT_PTRACED;
|
||||
if (capable(CAP_SYS_PTRACE))
|
||||
task->ptrace |= PT_PTRACE_CAP;
|
||||
|
||||
|
@ -229,6 +230,52 @@ out:
|
|||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* ptrace_traceme -- helper for PTRACE_TRACEME
|
||||
*
|
||||
* Performs checks and sets PT_PTRACED.
|
||||
* Should be used by all ptrace implementations for PTRACE_TRACEME.
|
||||
*/
|
||||
int ptrace_traceme(void)
|
||||
{
|
||||
int ret = -EPERM;
|
||||
|
||||
/*
|
||||
* Are we already being traced?
|
||||
*/
|
||||
repeat:
|
||||
task_lock(current);
|
||||
if (!current->ptrace) {
|
||||
/*
|
||||
* See ptrace_attach() comments about the locking here.
|
||||
*/
|
||||
unsigned long flags;
|
||||
if (!write_trylock_irqsave(&tasklist_lock, flags)) {
|
||||
task_unlock(current);
|
||||
do {
|
||||
cpu_relax();
|
||||
} while (!write_can_lock(&tasklist_lock));
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
ret = security_ptrace_traceme(current->parent);
|
||||
|
||||
/*
|
||||
* Check PF_EXITING to ensure ->real_parent has not passed
|
||||
* exit_ptrace(). Otherwise we don't report the error but
|
||||
* pretend ->real_parent untraces us right after return.
|
||||
*/
|
||||
if (!ret && !(current->real_parent->flags & PF_EXITING)) {
|
||||
current->ptrace = PT_PTRACED;
|
||||
__ptrace_link(current, current->real_parent);
|
||||
}
|
||||
|
||||
write_unlock_irqrestore(&tasklist_lock, flags);
|
||||
}
|
||||
task_unlock(current);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called with irqs disabled, returns true if childs should reap themselves.
|
||||
*/
|
||||
|
@ -567,52 +614,6 @@ int ptrace_request(struct task_struct *child, long request,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ptrace_traceme -- helper for PTRACE_TRACEME
|
||||
*
|
||||
* Performs checks and sets PT_PTRACED.
|
||||
* Should be used by all ptrace implementations for PTRACE_TRACEME.
|
||||
*/
|
||||
int ptrace_traceme(void)
|
||||
{
|
||||
int ret = -EPERM;
|
||||
|
||||
/*
|
||||
* Are we already being traced?
|
||||
*/
|
||||
repeat:
|
||||
task_lock(current);
|
||||
if (!(current->ptrace & PT_PTRACED)) {
|
||||
/*
|
||||
* See ptrace_attach() comments about the locking here.
|
||||
*/
|
||||
unsigned long flags;
|
||||
if (!write_trylock_irqsave(&tasklist_lock, flags)) {
|
||||
task_unlock(current);
|
||||
do {
|
||||
cpu_relax();
|
||||
} while (!write_can_lock(&tasklist_lock));
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
ret = security_ptrace_traceme(current->parent);
|
||||
|
||||
/*
|
||||
* Check PF_EXITING to ensure ->real_parent has not passed
|
||||
* exit_ptrace(). Otherwise we don't report the error but
|
||||
* pretend ->real_parent untraces us right after return.
|
||||
*/
|
||||
if (!ret && !(current->real_parent->flags & PF_EXITING)) {
|
||||
current->ptrace |= PT_PTRACED;
|
||||
__ptrace_link(current, current->real_parent);
|
||||
}
|
||||
|
||||
write_unlock_irqrestore(&tasklist_lock, flags);
|
||||
}
|
||||
task_unlock(current);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ptrace_get_task_struct -- grab a task struct reference for ptrace
|
||||
* @pid: process id to grab a task_struct reference of
|
||||
|
|
Loading…
Reference in New Issue