diff options
Diffstat (limited to 'arch/mips/kernel/ptrace.c')
-rw-r--r-- | arch/mips/kernel/ptrace.c | 123 |
1 files changed, 77 insertions, 46 deletions
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 018b68023..41deb8f18 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -9,6 +9,8 @@ #include <linux/mm.h> #include <linux/errno.h> #include <linux/ptrace.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/user.h> #include <asm/uaccess.h> @@ -255,7 +257,9 @@ static int write_long(struct task_struct * tsk, unsigned long addr, asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; + int res; + lock_kernel(); #if 0 printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n", (int) request, (int) pid, (unsigned long) addr, @@ -263,30 +267,43 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) #endif if (request == PTRACE_TRACEME) { /* are we already being traced? */ - if (current->flags & PF_PTRACED) - return -EPERM; + if (current->flags & PF_PTRACED) { + res = -EPERM; + goto out; + } /* set the ptrace bit in the process flags. */ current->flags |= PF_PTRACED; - return 0; + res = 0; + goto out; + } + if (pid == 1) { /* you may not mess with init */ + res = -EPERM; + goto out; + } + if (!(child = get_task(pid))) { + res = -ESRCH; + goto out; } - if (pid == 1) /* you may not mess with init */ - return -EPERM; - if (!(child = get_task(pid))) - return -ESRCH; if (request == PTRACE_ATTACH) { - if (child == current) - return -EPERM; + if (child == current) { + res = -EPERM; + goto out; + } if ((!child->dumpable || (current->uid != child->euid) || (current->uid != child->suid) || (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && !suser()) - return -EPERM; + (current->gid != child->gid)) && !suser()) { + res = -EPERM; + goto out; + } /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) - return -EPERM; + if (child->flags & PF_PTRACED) { + res = -EPERM; + goto out; + } child->flags |= PF_PTRACED; if (child->p_pptr != current) { REMOVE_LINKS(child); @@ -294,31 +311,35 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) SET_LINKS(child); } send_sig(SIGSTOP, child, 1); - return 0; + res = 0; + goto out; + } + if (!(child->flags & PF_PTRACED)) { + res = -ESRCH; + goto out; } - if (!(child->flags & PF_PTRACED)) - return -ESRCH; if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - return -ESRCH; + if (request != PTRACE_KILL) { + res = -ESRCH; + goto out; + } + } + if (child->p_pptr != current) { + res = -ESRCH; + goto out; } - if (child->p_pptr != current) - return -ESRCH; switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; - int res; res = read_long(child, addr, &tmp); if (res < 0) - return res; - res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); - if (!res) - put_user(tmp,(unsigned long *) data); - return res; + goto out; + res = put_user(tmp,(unsigned long *) data); + goto out; } /* read the word at location addr in the USER area. */ @@ -326,14 +347,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_PEEKUSR: { struct pt_regs *regs; unsigned long tmp; - int res; regs = (struct pt_regs *) (child->tss.ksp - sizeof(struct pt_regs)); - res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); - if(res < 0) - return res; - res = tmp = 0; /* Default return value. */ + tmp = 0; /* Default return value. */ if(addr < 32 && addr >= 0) { tmp = regs->regs[addr]; } else if(addr >= 32 && addr < 64) { @@ -370,18 +387,18 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) default: tmp = 0; res = -EIO; - break; + goto out; }; } - if(!res) - put_user(tmp, (unsigned long *) data); - return res; + res = put_user(tmp, (unsigned long *) data); + goto out; } /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: - return write_long(child,addr,data); + res = write_long(child,addr,data); + goto out; case PTRACE_POKEUSR: { struct pt_regs *regs; @@ -419,20 +436,23 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) break; }; } - return res; + goto out; } case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ - if ((unsigned long) data > NSIG) - return -EIO; + if ((unsigned long) data > NSIG) { + res = -EIO; + goto out; + } if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; else child->flags &= ~PF_TRACESYS; child->exit_code = data; wake_up_process(child); - return data; + res = data; + goto out; } /* @@ -445,24 +465,32 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) wake_up_process(child); child->exit_code = SIGKILL; } - return 0; + res = 0; + goto out; } case PTRACE_DETACH: { /* detach a process that was attached. */ - if ((unsigned long) data > NSIG) - return -EIO; + if ((unsigned long) data > NSIG) { + res = -EIO; + goto out; + } child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); child->exit_code = data; REMOVE_LINKS(child); child->p_pptr = child->p_opptr; SET_LINKS(child); - return 0; + res = 0; + goto out; } default: - return -EIO; + res = -EIO; + goto out; } +out: + unlock_kernel(); + return res; } asmlinkage void syscall_trace(void) @@ -479,7 +507,10 @@ asmlinkage void syscall_trace(void) * for normal use. strace only continues with a signal if the * stopping signal is not SIGTRAP. -brl */ - if (current->exit_code) + if (current->exit_code) { + spin_lock_irq(¤t->sigmask_lock); current->signal |= (1 << (current->exit_code - 1)); + spin_unlock_irq(¤t->sigmask_lock); + } current->exit_code = 0; } |