Commit 6b9c7ed8 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Linus Torvalds
Browse files

[PATCH] use ptrace_get_task_struct in various places



The ptrace_get_task_struct() helper that I added as part of the ptrace
consolidation is useful in variety of places that currently opencode it.
Switch them to the common helpers.

Add a ptrace_traceme() helper that needs to be explicitly called, and simplify
the ptrace_get_task_struct() interface.  We don't need the request argument
now, and we return the task_struct directly, using ERR_PTR() for error
returns.  It's a bit more code in the callers, but we have two sane routines
that do one thing well now.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 6b34350f
...@@ -265,30 +265,16 @@ do_sys_ptrace(long request, long pid, long addr, long data, ...@@ -265,30 +265,16 @@ do_sys_ptrace(long request, long pid, long addr, long data,
lock_kernel(); lock_kernel();
DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n", DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",
request, pid, addr, data)); request, pid, addr, data));
ret = -EPERM;
if (request == PTRACE_TRACEME) { if (request == PTRACE_TRACEME) {
/* are we already being traced? */ ret = ptrace_traceme();
if (current->ptrace & PT_PTRACED)
goto out_notsk;
ret = security_ptrace(current->parent, current);
if (ret)
goto out_notsk;
/* set the ptrace bit in the process ptrace flags. */
current->ptrace |= PT_PTRACED;
ret = 0;
goto out_notsk; goto out_notsk;
} }
if (pid == 1) /* you may not mess with init */
goto out_notsk;
ret = -ESRCH; child = ptrace_get_task_struct(pid);
read_lock(&tasklist_lock); if (IS_ERR(child)) {
child = find_task_by_pid(pid); ret = PTR_ERR(child);
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
if (!child)
goto out_notsk; goto out_notsk;
}
if (request == PTRACE_ATTACH) { if (request == PTRACE_ATTACH) {
ret = ptrace_attach(child); ret = ptrace_attach(child);
......
...@@ -1761,21 +1761,15 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data) ...@@ -1761,21 +1761,15 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data)
lock_kernel(); lock_kernel();
if (request == PTRACE_TRACEME) { if (request == PTRACE_TRACEME) {
ret = sys_ptrace(request, pid, addr, data); ret = ptrace_traceme();
goto out; goto out;
} }
ret = -ESRCH; child = ptrace_get_task_struct(pid);
read_lock(&tasklist_lock); if (IS_ERR(child)) {
child = find_task_by_pid(pid); ret = PTR_ERR(child);
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
if (!child)
goto out; goto out;
ret = -EPERM; }
if (pid == 1) /* no messing around with init! */
goto out_tsk;
if (request == PTRACE_ATTACH) { if (request == PTRACE_ATTACH) {
ret = sys_ptrace(request, pid, addr, data); ret = sys_ptrace(request, pid, addr, data);
......
...@@ -1422,14 +1422,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data) ...@@ -1422,14 +1422,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
lock_kernel(); lock_kernel();
ret = -EPERM; ret = -EPERM;
if (request == PTRACE_TRACEME) { if (request == PTRACE_TRACEME) {
/* are we already being traced? */ ret = ptrace_traceme();
if (current->ptrace & PT_PTRACED)
goto out;
ret = security_ptrace(current->parent, current);
if (ret)
goto out;
current->ptrace |= PT_PTRACED;
ret = 0;
goto out; goto out;
} }
......
...@@ -762,28 +762,16 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) ...@@ -762,28 +762,16 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
int ret; int ret;
lock_kernel(); lock_kernel();
ret = -EPERM;
if (request == PTRACE_TRACEME) { if (request == PTRACE_TRACEME) {
/* are we already being traced? */ ret = ptrace_traceme();
if (current->ptrace & PT_PTRACED)
goto out;
/* set the ptrace bit in the process flags. */
current->ptrace |= PT_PTRACED;
ret = 0;
goto out; goto out;
} }
ret = -ESRCH;
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
if (!child)
goto out;
ret = -EPERM; child = ptrace_get_task_struct(pid);
if (pid == 1) /* you may not mess with init */ if (IS_ERR(child)) {
ret = PTR_ERR(child);
goto out; goto out;
}
if (request == PTRACE_ATTACH) { if (request == PTRACE_ATTACH) {
ret = ptrace_attach(child); ret = ptrace_attach(child);
......
...@@ -57,30 +57,16 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) ...@@ -57,30 +57,16 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
(unsigned long) data); (unsigned long) data);
#endif #endif
lock_kernel(); lock_kernel();
ret = -EPERM;
if (request == PTRACE_TRACEME) { if (request == PTRACE_TRACEME) {
/* are we already being traced? */ ret = ptrace_traceme();
if (current->ptrace & PT_PTRACED)
goto out;
if ((ret = security_ptrace(current->parent, current)))
goto out;
/* set the ptrace bit in the process flags. */
current->ptrace |= PT_PTRACED;
ret = 0;
goto out; goto out;
} }
ret = -ESRCH;
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
if (!child)
goto out;
ret = -EPERM; child = ptrace_get_task_struct(pid);
if (pid == 1) /* you may not mess with init */ if (IS_ERR(child)) {
goto out_tsk; ret = PTR_ERR(child);
goto out;
}
if (request == PTRACE_ATTACH) { if (request == PTRACE_ATTACH) {
ret = ptrace_attach(child); ret = ptrace_attach(child);
......
...@@ -45,33 +45,19 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, ...@@ -45,33 +45,19 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
unsigned long data) unsigned long data)
{ {
struct task_struct *child; struct task_struct *child;
int ret = -EPERM; int ret;
lock_kernel(); lock_kernel();
if (request == PTRACE_TRACEME) { if (request == PTRACE_TRACEME) {
/* are we already being traced? */ ret = ptrace_traceme();
if (current->ptrace & PT_PTRACED)
goto out;
ret = security_ptrace(current->parent, current);
if (ret)
goto out;
/* set the ptrace bit in the process flags. */
current->ptrace |= PT_PTRACED;
ret = 0;
goto out; goto out;
} }
ret = -ESRCH;
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
if (!child)
goto out;
ret = -EPERM; child = ptrace_get_task_struct(pid);
if (pid == 1) /* you may not mess with init */ if (IS_ERR(child)) {
goto out_tsk; ret = PTR_ERR(child);
goto out;
}
if (request == PTRACE_ATTACH) { if (request == PTRACE_ATTACH) {
ret = ptrace_attach(child); ret = ptrace_attach(child);
......
...@@ -712,35 +712,18 @@ sys_ptrace(long request, long pid, long addr, long data) ...@@ -712,35 +712,18 @@ sys_ptrace(long request, long pid, long addr, long data)
int ret; int ret;
lock_kernel(); lock_kernel();
if (request == PTRACE_TRACEME) { if (request == PTRACE_TRACEME) {
/* are we already being traced? */ ret = ptrace_traceme();
ret = -EPERM; goto out;
if (current->ptrace & PT_PTRACED)
goto out;
ret = security_ptrace(current->parent, current);
if (ret)
goto out;
/* set the ptrace bit in the process flags. */
current->ptrace |= PT_PTRACED;
goto out;
} }
ret = -EPERM; child = ptrace_get_task_struct(pid);
if (pid == 1) /* you may not mess with init */ if (IS_ERR(child)) {
goto out; ret = PTR_ERR(child);
ret = -ESRCH;
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
if (!child)
goto out; goto out;
}
ret = do_ptrace(child, request, addr, data); ret = do_ptrace(child, request, addr, data);
put_task_struct(child); put_task_struct(child);
out: out:
unlock_kernel(); unlock_kernel();
......
...@@ -286,40 +286,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs) ...@@ -286,40 +286,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
s, (int) request, (int) pid, addr, data, addr2); s, (int) request, (int) pid, addr, data, addr2);
} }
#endif #endif
if (request == PTRACE_TRACEME) {
int my_ret;
/* are we already being traced? */
if (current->ptrace & PT_PTRACED) {
pt_error_return(regs, EPERM);
goto out;
}
my_ret = security_ptrace(current->parent, current);
if (my_ret) {
pt_error_return(regs, -my_ret);
goto out;
}
/* set the ptrace bit in the process flags. */ if (request == PTRACE_TRACEME) {
current->ptrace |= PT_PTRACED; ret = ptrace_traceme();
pt_succ_return(regs, 0); pt_succ_return(regs, 0);
goto out; goto out;
} }
#ifndef ALLOW_INIT_TRACING
if (pid == 1) {
/* Can't dork with init. */
pt_error_return(regs, EPERM);
goto out;
}
#endif
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
if (!child) { child = ptrace_get_task_struct(pid);
pt_error_return(regs, ESRCH); if (IS_ERR(child)) {
ret = PTR_ERR(child);
pt_error_return(regs, -ret);
goto out; goto out;
} }
......
...@@ -198,39 +198,15 @@ asmlinkage void do_ptrace(struct pt_regs *regs) ...@@ -198,39 +198,15 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
} }
#endif #endif
if (request == PTRACE_TRACEME) { if (request == PTRACE_TRACEME) {
int ret; ret = ptrace_traceme();
/* are we already being traced? */
if (current->ptrace & PT_PTRACED) {
pt_error_return(regs, EPERM);
goto out;
}
ret = security_ptrace(current->parent, current);
if (ret) {
pt_error_return(regs, -ret);
goto out;
}
/* set the ptrace bit in the process flags. */
current->ptrace |= PT_PTRACED;
pt_succ_return(regs, 0); pt_succ_return(regs, 0);
goto out; goto out;
} }
#ifndef ALLOW_INIT_TRACING
if (pid == 1) {
/* Can't dork with init. */
pt_error_return(regs, EPERM);
goto out;
}
#endif
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
if (!child) { child = ptrace_get_task_struct(pid);
pt_error_return(regs, ESRCH); if (IS_ERR(child)) {
ret = PTR_ERR(child);
pt_error_return(regs, -ret);
goto out; goto out;
} }
......
...@@ -196,36 +196,6 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val) ...@@ -196,36 +196,6 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
#undef R32 #undef R32
static struct task_struct *find_target(int request, int pid, int *err)
{
struct task_struct *child;
*err = -EPERM;
if (pid == 1)
return NULL;
*err = -ESRCH;
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
if (child)
get_task_struct(child);
read_unlock(&tasklist_lock);
if (child) {
*err = -EPERM;
if (child->pid == 1)
goto out;
*err = ptrace_check_attach(child, request == PTRACE_KILL);
if (*err < 0)
goto out;
return child;
}
out:
if (child)
put_task_struct(child);
return NULL;
}
asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
{ {
struct task_struct *child; struct task_struct *child;
...@@ -254,9 +224,16 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) ...@@ -254,9 +224,16 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
break; break;
} }
child = find_target(request, pid, &ret); if (request == PTRACE_TRACEME)
if (!child) return ptrace_traceme();
return ret;
child = ptrace_get_task_struct(pid);
if (IS_ERR(child))
return PTR_ERR(child);
ret = ptrace_check_attach(child, request == PTRACE_KILL);
if (ret < 0)
goto out;
childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs)); childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs));
...@@ -373,6 +350,7 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) ...@@ -373,6 +350,7 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
break; break;
} }
out:
put_task_struct(child); put_task_struct(child);
return ret; return ret;
} }
......
...@@ -80,6 +80,8 @@ ...@@ -80,6 +80,8 @@
extern long arch_ptrace(struct task_struct *child, long request, long addr, long data); extern long arch_ptrace(struct task_struct *child, long request, long addr, long data);
extern struct task_struct *ptrace_get_task_struct(pid_t pid);
extern int ptrace_traceme(void);
extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len); extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len);
extern int ptrace_attach(struct task_struct *tsk); extern int ptrace_attach(struct task_struct *tsk);
......
...@@ -408,54 +408,62 @@ int ptrace_request(struct task_struct *child, long request, ...@@ -408,54 +408,62 @@ int ptrace_request(struct task_struct *child, long request,
return ret; return ret;
} }
#ifndef __ARCH_SYS_PTRACE /**
static int ptrace_get_task_struct(long request, long pid, * ptrace_traceme -- helper for PTRACE_TRACEME
struct task_struct **childp) *
* Performs checks and sets PT_PTRACED.
* Should be used by all ptrace implementations for PTRACE_TRACEME.
*/
int ptrace_traceme(void)
{ {
struct task_struct *child;
int ret; int ret;
/* /*
* Callers use child == NULL as an indication to exit early even * Are we already being traced?
* when the return value is 0, so make sure it is non-NULL here. */
if (current->ptrace & PT_PTRACED)
return -EPERM;
ret = security_ptrace(current->parent, current);
if (ret)
return -EPERM;
/*
* Set the ptrace bit in the process ptrace flags.
*/ */
*childp = NULL; current->ptrace |= PT_PTRACED;
return 0;
}
if (request == PTRACE_TRACEME) { /**
/* * ptrace_get_task_struct -- grab a task struct reference for ptrace
* Are we already being traced? * @pid: process id to grab a task_struct reference of
*/ *
if (current->ptrace & PT_PTRACED) * This function is a helper for ptrace implementations. It checks
return -EPERM; * permissions and then grabs a task struct for use of the actual
ret = security_ptrace(current->parent, current); * ptrace implementation.
if (ret) *
return -EPERM; * Returns the task_struct for @pid or an ERR_PTR() on failure.
/* */
* Set the ptrace bit in the process ptrace flags. struct task_struct *ptrace_get_task_struct(pid_t pid)
*/ {
current->ptrace |= PT_PTRACED; struct task_struct *child;
return 0;
}
/* /*
* You may not mess with init * Tracing init is not allowed.
*/ */
if (pid == 1) if (pid == 1)
return -EPERM; return ERR_PTR(-EPERM);
ret = -ESRCH;
read_lock(&tasklist_lock); read_lock(&tasklist_lock);
child = find_task_by_pid(pid); child = find_task_by_pid(pid);
if (child) if (child)
get_task_struct(child); get_task_struct(child);
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
if (!child) if (!child)
return -ESRCH; return ERR_PTR(-ESRCH);
return child;
*childp = child;
return 0;
} }
#ifndef __ARCH_SYS_PTRACE
asmlinkage long sys_ptrace(long request, long pid, long addr, long data) asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
{ {
struct task_struct *child; struct task_struct *child;
...@@ -465,9 +473,16 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) ...@@ -465,9 +473,16 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
* This lock_kernel fixes a subtle race with suid exec * This lock_kernel fixes a subtle race with suid exec
*/ */
lock_kernel(); lock_kernel();
ret = ptrace_get_task_struct(request, pid, &child); if (request == PTRACE_TRACEME) {
if (!child) ret = ptrace_traceme();
goto out; goto out;
}
child = ptrace_get_task_struct(pid);
if (IS_ERR(child)) {
ret = PTR_ERR(child);
goto out;
}
if (request == PTRACE_ATTACH) { if (request == PTRACE_ATTACH) {
ret = ptrace_attach(child);