fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / sparc / kernel / ptrace.c
index 949072b..11cf861 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/security.h>
+#include <linux/signal.h>
+#include <linux/vs_base.h>
 
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -48,9 +50,9 @@ static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
 }
 
 static void
-pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long *addr)
+pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long __user *addr)
 {
-       if (put_user(value, (long __user *) addr)) {
+       if (put_user(value, addr)) {
                pt_error_return(regs, EFAULT);
                return;
        }
@@ -61,7 +63,7 @@ pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long *addr)
 }
 
 static void
-pt_os_succ_return (struct pt_regs *regs, unsigned long val, long *addr)
+pt_os_succ_return (struct pt_regs *regs, unsigned long val, long __user *addr)
 {
        if (current->personality == PER_SUNOS)
                pt_succ_return (regs, val);
@@ -71,10 +73,10 @@ pt_os_succ_return (struct pt_regs *regs, unsigned long val, long *addr)
 
 /* Fuck me gently with a chainsaw... */
 static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
-                                  struct task_struct *tsk, long *addr)
+                                  struct task_struct *tsk, long __user *addr)
 {
        struct pt_regs *cregs = tsk->thread.kregs;
-       struct thread_info *t = tsk->thread_info;
+       struct thread_info *t = task_thread_info(tsk);
        int v;
        
        if(offset >= 1024)
@@ -169,7 +171,7 @@ static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
                                    struct task_struct *tsk)
 {
        struct pt_regs *cregs = tsk->thread.kregs;
-       struct thread_info *t = tsk->thread_info;
+       struct thread_info *t = task_thread_info(tsk);
        unsigned long value = regs->u_regs[UREG_I3];
 
        if(offset >= 1024)
@@ -285,43 +287,23 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                               s, (int) request, (int) pid, addr, data, addr2);
        }
 #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) {
+       if (request == PTRACE_TRACEME) {
+               ret = ptrace_traceme();
+               if (ret < 0)
                        pt_error_return(regs, -ret);
-                       goto out;
-               }
-
-               /* set the ptrace bit in the process flags. */
-               current->ptrace |= PT_PTRACED;
-               pt_succ_return(regs, 0);
-               goto out;
-       }
-#ifndef ALLOW_INIT_TRACING
-       if(pid == 1) {
-               /* Can't dork with init. */
-               pt_error_return(regs, EPERM);
+               else
+                       pt_succ_return(regs, 0);
                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;
        }
-       if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) {
+       if (!vx_check(vx_task_xid(child), VS_WATCH_P|VS_IDENT)) {
                pt_error_return(regs, ESRCH);
                goto out_tsk;
        }
@@ -349,14 +331,14 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
 
                if (access_process_vm(child, addr,
                                      &tmp, sizeof(tmp), 0) == sizeof(tmp))
-                       pt_os_succ_return(regs, tmp, (long *)data);
+                       pt_os_succ_return(regs, tmp, (long __user *)data);
                else
                        pt_error_return(regs, EIO);
                goto out_tsk;
        }
 
        case PTRACE_PEEKUSR:
-               read_sunos_user(regs, addr, child, (long *) data);
+               read_sunos_user(regs, addr, child, (long __user *) data);
                goto out_tsk;
 
        case PTRACE_POKEUSR:
@@ -378,8 +360,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                struct pt_regs *cregs = child->thread.kregs;
                int rval;
 
-               rval = verify_area(VERIFY_WRITE, pregs, sizeof(struct pt_regs));
-               if(rval) {
+               if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) {
+                       rval = -EFAULT;
                        pt_error_return(regs, -rval);
                        goto out_tsk;
                }
@@ -405,9 +387,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                /* Must be careful, tracing process can only set certain
                 * bits in the psr.
                 */
-               i = verify_area(VERIFY_READ, pregs, sizeof(struct pt_regs));
-               if(i) {
-                       pt_error_return(regs, -i);
+               if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) {
+                       pt_error_return(regs, EFAULT);
                        goto out_tsk;
                }
                __get_user(psr, (&pregs->psr));
@@ -417,7 +398,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                psr &= PSR_ICC;
                cregs->psr &= ~PSR_ICC;
                cregs->psr |= psr;
-               if(!((pc | npc) & 3)) {
+               if (!((pc | npc) & 3)) {
                        cregs->pc = pc;
                        cregs->npc =npc;
                }
@@ -443,8 +424,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                struct fps __user *fps = (struct fps __user *) addr;
                int i;
 
-               i = verify_area(VERIFY_WRITE, fps, sizeof(struct fps));
-               if(i) {
+               if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) {
+                       i = -EFAULT;
                        pt_error_return(regs, -i);
                        goto out_tsk;
                }
@@ -478,8 +459,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                struct fps __user *fps = (struct fps __user *) addr;
                int i;
 
-               i = verify_area(VERIFY_READ, fps, sizeof(struct fps));
-               if(i) {
+               if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) {
+                       i = -EFAULT;
                        pt_error_return(regs, -i);
                        goto out_tsk;
                }
@@ -531,22 +512,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                addr = 1;
 
        case PTRACE_CONT: { /* restart after signal. */
-               if (data > _NSIG) {
+               if (!valid_signal(data)) {
                        pt_error_return(regs, EIO);
                        goto out_tsk;
                }
-               if (addr != 1) {
-                       if (addr & 3) {
-                               pt_error_return(regs, EINVAL);
-                               goto out_tsk;
-                       }
-#ifdef DEBUG_PTRACE
-                       printk ("Original: %08lx %08lx\n", child->thread.kregs->pc, child->thread.kregs->npc);
-                       printk ("Continuing with %08lx %08lx\n", addr, addr+4);
-#endif
-                       child->thread.kregs->pc = addr;
-                       child->thread.kregs->npc = addr + 4;
-               }
 
                if (request == PTRACE_SYSCALL)
                        set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -571,7 +540,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
  * exit.
  */
        case PTRACE_KILL: {
-               if (child->state == TASK_ZOMBIE) {      /* already dead */
+               if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
                        pt_succ_return(regs, 0);
                        goto out_tsk;
                }
@@ -618,12 +587,9 @@ asmlinkage void syscall_trace(void)
                return;
        if (!(current->ptrace & PT_PTRACED))
                return;
-       current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-                                       ? 0x80 : 0);
-       current->state = TASK_STOPPED;
        current->thread.flags ^= MAGIC_CONSTANT;
-       notify_parent(current, SIGCHLD);
-       schedule();
+       ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+                                ? 0x80 : 0));
        /*
         * this isn't the same as continuing with a signal, but it will do
         * for normal use.  strace only continues with a signal if the