[PATCH] use ptrace_get_task_struct in various places
[sfrench/cifs-2.6.git] / arch / ia64 / kernel / ptrace.c
index 575a8f657b3129bacc8ec2979470ecc84c9b7b3f..8d88eeea02d12fa762a1d54ba71ce15be73529c9 100644 (file)
@@ -587,8 +587,9 @@ thread_matches (struct task_struct *thread, unsigned long addr)
 static struct task_struct *
 find_thread_for_addr (struct task_struct *child, unsigned long addr)
 {
-       struct task_struct *g, *p;
+       struct task_struct *p;
        struct mm_struct *mm;
+       struct list_head *this, *next;
        int mm_users;
 
        if (!(mm = get_task_mm(child)))
@@ -600,28 +601,21 @@ find_thread_for_addr (struct task_struct *child, unsigned long addr)
                goto out;               /* not multi-threaded */
 
        /*
-        * First, traverse the child's thread-list.  Good for scalability with
-        * NPTL-threads.
+        * Traverse the current process' children list.  Every task that
+        * one attaches to becomes a child.  And it is only attached children
+        * of the debugger that are of interest (ptrace_check_attach checks
+        * for this).
         */
-       p = child;
-       do {
-               if (thread_matches(p, addr)) {
-                       child = p;
-                       goto out;
-               }
-               if (mm_users-- <= 1)
-                       goto out;
-       } while ((p = next_thread(p)) != child);
-
-       do_each_thread(g, p) {
-               if (child->mm != mm)
+       list_for_each_safe(this, next, &current->children) {
+               p = list_entry(this, struct task_struct, sibling);
+               if (p->mm != mm)
                        continue;
-
                if (thread_matches(p, addr)) {
                        child = p;
                        goto out;
                }
-       } while_each_thread(g, p);
+       }
+
   out:
        mmput(mm);
        return child;
@@ -725,12 +719,32 @@ convert_to_non_syscall (struct task_struct *child, struct pt_regs  *pt,
                        break;
        }
 
+       /*
+        * Note: at the time of this call, the target task is blocked
+        * in notify_resume_user() and by clearling PRED_LEAVE_SYSCALL
+        * (aka, "pLvSys") we redirect execution from
+        * .work_pending_syscall_end to .work_processed_kernel.
+        */
        unw_get_pr(&prev_info, &pr);
-       pr &= ~(1UL << PRED_SYSCALL);
+       pr &= ~((1UL << PRED_SYSCALL) | (1UL << PRED_LEAVE_SYSCALL));
        pr |=  (1UL << PRED_NON_SYSCALL);
        unw_set_pr(&prev_info, pr);
 
        pt->cr_ifs = (1UL << 63) | cfm;
+       /*
+        * Clear the memory that is NOT written on syscall-entry to
+        * ensure we do not leak kernel-state to user when execution
+        * resumes.
+        */
+       pt->r2 = 0;
+       pt->r3 = 0;
+       pt->r14 = 0;
+       memset(&pt->r16, 0, 16*8);      /* clear r16-r31 */
+       memset(&pt->f6, 0, 6*16);       /* clear f6-f11 */
+       pt->b7 = 0;
+       pt->ar_ccv = 0;
+       pt->ar_csd = 0;
+       pt->ar_ssd = 0;
 }
 
 static int
@@ -945,6 +959,13 @@ access_uarea (struct task_struct *child, unsigned long addr,
                                *data = (pt->cr_ipsr & IPSR_MASK);
                        return 0;
 
+                     case PT_AR_RSC:
+                       if (write_access)
+                               pt->ar_rsc = *data | (3 << 2); /* force PL3 */
+                       else
+                               *data = pt->ar_rsc;
+                       return 0;
+
                      case PT_AR_RNAT:
                        urbs_end = ia64_get_user_rbs_end(child, pt, NULL);
                        rnat_addr = (long) ia64_rse_rnat_addr((long *)
@@ -996,9 +1017,6 @@ access_uarea (struct task_struct *child, unsigned long addr,
                      case PT_AR_BSPSTORE:
                        ptr = pt_reg_addr(pt, ar_bspstore);
                        break;
-                     case PT_AR_RSC:
-                       ptr = pt_reg_addr(pt, ar_rsc);
-                       break;
                      case PT_AR_UNAT:
                        ptr = pt_reg_addr(pt, ar_unat);
                        break;
@@ -1234,7 +1252,7 @@ ptrace_getregs (struct task_struct *child, struct pt_all_user_regs __user *ppr)
 static long
 ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr)
 {
-       unsigned long psr, ec, lc, rnat, bsp, cfm, nat_bits, val = 0;
+       unsigned long psr, rsc, ec, lc, rnat, bsp, cfm, nat_bits, val = 0;
        struct unw_frame_info info;
        struct switch_stack *sw;
        struct ia64_fpreg fpval;
@@ -1267,7 +1285,7 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr)
        /* app regs */
 
        retval |= __get_user(pt->ar_pfs, &ppr->ar[PT_AUR_PFS]);
-       retval |= __get_user(pt->ar_rsc, &ppr->ar[PT_AUR_RSC]);
+       retval |= __get_user(rsc, &ppr->ar[PT_AUR_RSC]);
        retval |= __get_user(pt->ar_bspstore, &ppr->ar[PT_AUR_BSPSTORE]);
        retval |= __get_user(pt->ar_unat, &ppr->ar[PT_AUR_UNAT]);
        retval |= __get_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]);
@@ -1365,6 +1383,7 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr)
        retval |= __get_user(nat_bits, &ppr->nat);
 
        retval |= access_uarea(child, PT_CR_IPSR, &psr, 1);
+       retval |= access_uarea(child, PT_AR_RSC, &rsc, 1);
        retval |= access_uarea(child, PT_AR_EC, &ec, 1);
        retval |= access_uarea(child, PT_AR_LC, &lc, 1);
        retval |= access_uarea(child, PT_AR_RNAT, &rnat, 1);
@@ -1403,14 +1422,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
        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;
        }