From: Christoph Hellwig 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: Christoph Hellwig Signed-off-by: Andrew Morton --- arch/alpha/kernel/ptrace.c | 24 ++----------- arch/ia64/ia32/sys_ia32.c | 16 ++------ arch/ia64/kernel/ptrace.c | 9 ---- arch/m32r/kernel/ptrace.c | 22 ++---------- arch/mips/kernel/ptrace32.c | 26 +++----------- arch/powerpc/kernel/ptrace32.c | 30 ++++------------ arch/s390/kernel/ptrace.c | 29 +++------------ arch/sparc/kernel/ptrace.c | 35 +++---------------- arch/sparc64/kernel/ptrace.c | 34 ++---------------- arch/x86_64/ia32/ptrace32.c | 44 ++++++------------------ include/linux/ptrace.h | 2 + kernel/ptrace.c | 75 ++++++++++++++++++++++++----------------- 12 files changed, 105 insertions(+), 241 deletions(-) diff -puN arch/alpha/kernel/ptrace.c~use-ptrace_get_task_struct-in-various-places-2 arch/alpha/kernel/ptrace.c --- devel/arch/alpha/kernel/ptrace.c~use-ptrace_get_task_struct-in-various-places-2 2005-11-22 22:30:46.000000000 -0800 +++ devel-akpm/arch/alpha/kernel/ptrace.c 2005-11-22 22:30:46.000000000 -0800 @@ -265,30 +265,16 @@ do_sys_ptrace(long request, long pid, lo lock_kernel(); DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n", request, pid, addr, data)); - ret = -EPERM; if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - 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; + ret = ptrace_traceme(); goto out_notsk; } - if (pid == 1) /* you may not mess with init */ - goto out_notsk; - ret = -ESRCH; - 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); + if (IS_ERR(child)) { + ret = PTR_ERR(child); goto out_notsk; + } if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); diff -puN arch/ia64/ia32/sys_ia32.c~use-ptrace_get_task_struct-in-various-places-2 arch/ia64/ia32/sys_ia32.c --- devel/arch/ia64/ia32/sys_ia32.c~use-ptrace_get_task_struct-in-various-places-2 2005-11-22 22:30:46.000000000 -0800 +++ devel-akpm/arch/ia64/ia32/sys_ia32.c 2005-11-22 22:30:46.000000000 -0800 @@ -1761,21 +1761,15 @@ sys32_ptrace (int request, pid_t pid, un lock_kernel(); if (request == PTRACE_TRACEME) { - ret = sys_ptrace(request, pid, addr, data); + ret = ptrace_traceme(); 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) + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); goto out; - ret = -EPERM; - if (pid == 1) /* no messing around with init! */ - goto out_tsk; + } if (request == PTRACE_ATTACH) { ret = sys_ptrace(request, pid, addr, data); diff -puN arch/ia64/kernel/ptrace.c~use-ptrace_get_task_struct-in-various-places-2 arch/ia64/kernel/ptrace.c --- devel/arch/ia64/kernel/ptrace.c~use-ptrace_get_task_struct-in-various-places-2 2005-11-22 22:30:46.000000000 -0800 +++ devel-akpm/arch/ia64/kernel/ptrace.c 2005-11-22 22:30:46.000000000 -0800 @@ -1422,14 +1422,7 @@ sys_ptrace (long request, pid_t pid, uns lock_kernel(); ret = -EPERM; if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - current->ptrace |= PT_PTRACED; - ret = 0; + ret = ptrace_traceme(); goto out; } diff -puN arch/m32r/kernel/ptrace.c~use-ptrace_get_task_struct-in-various-places-2 arch/m32r/kernel/ptrace.c --- devel/arch/m32r/kernel/ptrace.c~use-ptrace_get_task_struct-in-various-places-2 2005-11-22 22:30:46.000000000 -0800 +++ devel-akpm/arch/m32r/kernel/ptrace.c 2005-11-22 22:30:46.000000000 -0800 @@ -762,28 +762,16 @@ asmlinkage long sys_ptrace(long request, int ret; lock_kernel(); - ret = -EPERM; if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; + ret = ptrace_traceme(); 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; - if (pid == 1) /* you may not mess with init */ + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); goto out; + } if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); diff -puN arch/mips/kernel/ptrace32.c~use-ptrace_get_task_struct-in-various-places-2 arch/mips/kernel/ptrace32.c --- devel/arch/mips/kernel/ptrace32.c~use-ptrace_get_task_struct-in-various-places-2 2005-11-22 22:30:46.000000000 -0800 +++ devel-akpm/arch/mips/kernel/ptrace32.c 2005-11-22 22:30:46.000000000 -0800 @@ -57,30 +57,16 @@ asmlinkage int sys32_ptrace(int request, (unsigned long) data); #endif lock_kernel(); - ret = -EPERM; if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - 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; + ret = ptrace_traceme(); 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; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); + goto out; + } if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); diff -puN arch/powerpc/kernel/ptrace32.c~use-ptrace_get_task_struct-in-various-places-2 arch/powerpc/kernel/ptrace32.c --- devel/arch/powerpc/kernel/ptrace32.c~use-ptrace_get_task_struct-in-various-places-2 2005-11-22 22:30:46.000000000 -0800 +++ devel-akpm/arch/powerpc/kernel/ptrace32.c 2005-11-22 22:30:46.000000000 -0800 @@ -45,33 +45,19 @@ long compat_sys_ptrace(int request, int unsigned long data) { struct task_struct *child; - int ret = -EPERM; + int ret; lock_kernel(); - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - 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; + if (request == PTRACE_TRACEME) {= + ret = ptrace_traceme(); 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; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); + goto out; + } if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); diff -puN arch/s390/kernel/ptrace.c~use-ptrace_get_task_struct-in-various-places-2 arch/s390/kernel/ptrace.c --- devel/arch/s390/kernel/ptrace.c~use-ptrace_get_task_struct-in-various-places-2 2005-11-22 22:30:46.000000000 -0800 +++ devel-akpm/arch/s390/kernel/ptrace.c 2005-11-22 22:30:46.000000000 -0800 @@ -712,35 +712,18 @@ sys_ptrace(long request, long pid, long int ret; lock_kernel(); - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - ret = -EPERM; - 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 = ptrace_traceme(); + goto out; } - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - 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) + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); goto out; + } ret = do_ptrace(child, request, addr, data); - put_task_struct(child); out: unlock_kernel(); diff -puN arch/sparc64/kernel/ptrace.c~use-ptrace_get_task_struct-in-various-places-2 arch/sparc64/kernel/ptrace.c --- devel/arch/sparc64/kernel/ptrace.c~use-ptrace_get_task_struct-in-various-places-2 2005-11-22 22:30:46.000000000 -0800 +++ devel-akpm/arch/sparc64/kernel/ptrace.c 2005-11-22 22:30:46.000000000 -0800 @@ -198,39 +198,15 @@ asmlinkage void do_ptrace(struct pt_regs } #endif if (request == PTRACE_TRACEME) { - int ret; - - /* 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; + ret = ptrace_traceme(); pt_succ_return(regs, 0); 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) { - pt_error_return(regs, ESRCH); + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); + pt_error_return(regs, -ret); goto out; } diff -puN arch/sparc/kernel/ptrace.c~use-ptrace_get_task_struct-in-various-places-2 arch/sparc/kernel/ptrace.c --- devel/arch/sparc/kernel/ptrace.c~use-ptrace_get_task_struct-in-various-places-2 2005-11-22 22:30:46.000000000 -0800 +++ devel-akpm/arch/sparc/kernel/ptrace.c 2005-11-22 22:30:46.000000000 -0800 @@ -286,40 +286,17 @@ asmlinkage void do_ptrace(struct pt_regs s, (int) request, (int) pid, addr, data, addr2); } #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. */ - current->ptrace |= PT_PTRACED; + if (request == PTRACE_TRACEME) { + ret = ptrace_traceme(); pt_succ_return(regs, 0); 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) { - pt_error_return(regs, ESRCH); + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); + pt_error_return(regs, -ret); goto out; } diff -puN arch/x86_64/ia32/ptrace32.c~use-ptrace_get_task_struct-in-various-places-2 arch/x86_64/ia32/ptrace32.c --- devel/arch/x86_64/ia32/ptrace32.c~use-ptrace_get_task_struct-in-various-places-2 2005-11-22 22:30:46.000000000 -0800 +++ devel-akpm/arch/x86_64/ia32/ptrace32.c 2005-11-22 22:30:46.000000000 -0800 @@ -196,36 +196,6 @@ static int getreg32(struct task_struct * #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) { struct task_struct *child; @@ -254,9 +224,16 @@ asmlinkage long sys32_ptrace(long reques break; } - child = find_target(request, pid, &ret); - if (!child) - return ret; + if (request == PTRACE_TRACEME) + return ptrace_traceme(); + + 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)); @@ -373,6 +350,7 @@ asmlinkage long sys32_ptrace(long reques break; } + out: put_task_struct(child); return ret; } diff -puN include/linux/ptrace.h~use-ptrace_get_task_struct-in-various-places-2 include/linux/ptrace.h --- devel/include/linux/ptrace.h~use-ptrace_get_task_struct-in-various-places-2 2005-11-22 22:30:46.000000000 -0800 +++ devel-akpm/include/linux/ptrace.h 2005-11-22 22:30:46.000000000 -0800 @@ -80,6 +80,8 @@ 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_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); extern int ptrace_attach(struct task_struct *tsk); diff -puN kernel/ptrace.c~use-ptrace_get_task_struct-in-various-places-2 kernel/ptrace.c --- devel/kernel/ptrace.c~use-ptrace_get_task_struct-in-various-places-2 2005-11-22 22:30:46.000000000 -0800 +++ devel-akpm/kernel/ptrace.c 2005-11-22 22:30:46.000000000 -0800 @@ -407,54 +407,62 @@ int ptrace_request(struct task_struct *c return ret; } -#ifndef __ARCH_SYS_PTRACE -static int ptrace_get_task_struct(long request, long pid, - struct task_struct **childp) +/** + * 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) { - struct task_struct *child; int ret; /* - * Callers use child == NULL as an indication to exit early even - * when the return value is 0, so make sure it is non-NULL here. + * Are we already being traced? + */ + 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) { - /* - * Are we already being traced? - */ - 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. - */ - current->ptrace |= PT_PTRACED; - return 0; - } +/** + * ptrace_get_task_struct -- grab a task struct reference for ptrace + * @pid: process id to grab a task_struct reference of + * + * This function is a helper for ptrace implementations. It checks + * permissions and then grabs a task struct for use of the actual + * ptrace implementation. + * + * Returns the task_struct for @pid or an ERR_PTR() on failure. + */ +struct task_struct *ptrace_get_task_struct(pid_t pid) +{ + struct task_struct *child; /* - * You may not mess with init + * Tracing init is not allowed. */ if (pid == 1) - return -EPERM; + return ERR_PTR(-EPERM); - ret = -ESRCH; read_lock(&tasklist_lock); child = find_task_by_pid(pid); if (child) get_task_struct(child); read_unlock(&tasklist_lock); if (!child) - return -ESRCH; - - *childp = child; + return ERR_PTR(-ESRCH); return 0; } +#ifndef __ARCH_SYS_PTRACE asmlinkage long sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; @@ -464,9 +472,16 @@ asmlinkage long sys_ptrace(long request, * This lock_kernel fixes a subtle race with suid exec */ lock_kernel(); - ret = ptrace_get_task_struct(request, pid, &child); - if (!child) + if (request == PTRACE_TRACEME) { + ret = ptrace_traceme(); goto out; + } + + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); + goto out; + } if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); _