[SPARC]: Fix several regset and ptrace bugs.

1) ptrace should pass 'current' to task_user_regset_view()

2) When fetching general registers using a 64-bit view, and
the target is 32-bit, we have to convert.

3) Skip the whole register window get/set code block if
the user isn't asking to access anything in there.

Otherwise we have problems if the user doesn't have
an address space setup. Fetching ptrace register is
still valid at such a time, and ptrace does not try
to access the register window area of the regset.

Signed-off-by: David S. Miller <davem@davemloft.net>

+98 -52
+1 -1
arch/sparc/kernel/ptrace.c
··· 325 const struct user_regset_view *view; 326 int ret; 327 328 - view = task_user_regset_view(child); 329 330 switch(request) { 331 case PTRACE_GETREGS: {
··· 325 const struct user_regset_view *view; 326 int ret; 327 328 + view = task_user_regset_view(current); 329 330 switch(request) { 331 case PTRACE_GETREGS: {
+97 -51
arch/sparc64/kernel/ptrace.c
··· 114 preempt_enable(); 115 } 116 117 enum sparc_regset { 118 REGSET_GENERAL, 119 REGSET_FP, ··· 212 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 213 regs->u_regs, 214 0, 16 * sizeof(u64)); 215 - if (!ret) { 216 - unsigned long __user *reg_window = (unsigned long __user *) 217 - (regs->u_regs[UREG_I6] + STACK_BIAS); 218 - unsigned long window[16]; 219 220 - if (target == current) { 221 - if (copy_from_user(window, reg_window, sizeof(window))) 222 - return -EFAULT; 223 - } else { 224 - if (access_process_vm(target, 225 - (unsigned long) reg_window, 226 - window, 227 - sizeof(window), 0) != 228 - sizeof(window)) 229 - return -EFAULT; 230 - } 231 - 232 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 233 - window, 234 16 * sizeof(u64), 235 32 * sizeof(u64)); 236 } ··· 240 36 * sizeof(u64)); 241 } 242 243 - if (!ret) 244 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 245 36 * sizeof(u64), -1); 246 247 return ret; 248 } 249 ··· 262 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 263 regs->u_regs, 264 0, 16 * sizeof(u64)); 265 - if (!ret && count > 0) { 266 - unsigned long __user *reg_window = (unsigned long __user *) 267 - (regs->u_regs[UREG_I6] + STACK_BIAS); 268 - unsigned long window[16]; 269 270 - if (target == current) { 271 - if (copy_from_user(window, reg_window, sizeof(window))) 272 - return -EFAULT; 273 - } else { 274 - if (access_process_vm(target, 275 - (unsigned long) reg_window, 276 - window, 277 - sizeof(window), 0) != 278 - sizeof(window)) 279 - return -EFAULT; 280 - } 281 282 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 283 - window, 284 16 * sizeof(u64), 285 32 * sizeof(u64)); 286 - if (!ret) { 287 - if (target == current) { 288 - if (copy_to_user(reg_window, window, 289 - sizeof(window))) 290 - return -EFAULT; 291 - } else { 292 - if (access_process_vm(target, 293 - (unsigned long) 294 - reg_window, 295 - window, 296 - sizeof(window), 1) != 297 - sizeof(window)) 298 - return -EFAULT; 299 - } 300 - } 301 } 302 303 if (!ret && count > 0) { ··· 851 long compat_arch_ptrace(struct task_struct *child, compat_long_t request, 852 compat_ulong_t caddr, compat_ulong_t cdata) 853 { 854 - const struct user_regset_view *view = task_user_regset_view(child); 855 compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4]; 856 struct pt_regs32 __user *pregs; 857 struct compat_fps __user *fps; ··· 959 960 long arch_ptrace(struct task_struct *child, long request, long addr, long data) 961 { 962 - const struct user_regset_view *view = task_user_regset_view(child); 963 unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; 964 struct pt_regs __user *pregs; 965 struct fps __user *fps;
··· 114 preempt_enable(); 115 } 116 117 + static int get_from_target(struct task_struct *target, unsigned long uaddr, 118 + void *kbuf, int len) 119 + { 120 + if (target == current) { 121 + if (copy_from_user(kbuf, (void __user *) uaddr, len)) 122 + return -EFAULT; 123 + } else { 124 + int len2 = access_process_vm(target, uaddr, kbuf, len, 0); 125 + if (len2 != len) 126 + return -EFAULT; 127 + } 128 + return 0; 129 + } 130 + 131 + static int set_to_target(struct task_struct *target, unsigned long uaddr, 132 + void *kbuf, int len) 133 + { 134 + if (target == current) { 135 + if (copy_to_user((void __user *) uaddr, kbuf, len)) 136 + return -EFAULT; 137 + } else { 138 + int len2 = access_process_vm(target, uaddr, kbuf, len, 1); 139 + if (len2 != len) 140 + return -EFAULT; 141 + } 142 + return 0; 143 + } 144 + 145 + static int regwindow64_get(struct task_struct *target, 146 + const struct pt_regs *regs, 147 + struct reg_window *wbuf) 148 + { 149 + unsigned long rw_addr = regs->u_regs[UREG_I6]; 150 + 151 + if (test_tsk_thread_flag(current, TIF_32BIT)) { 152 + struct reg_window32 win32; 153 + int i; 154 + 155 + if (get_from_target(target, rw_addr, &win32, sizeof(win32))) 156 + return -EFAULT; 157 + for (i = 0; i < 8; i++) 158 + wbuf->locals[i] = win32.locals[i]; 159 + for (i = 0; i < 8; i++) 160 + wbuf->ins[i] = win32.ins[i]; 161 + } else { 162 + rw_addr += STACK_BIAS; 163 + if (get_from_target(target, rw_addr, wbuf, sizeof(*wbuf))) 164 + return -EFAULT; 165 + } 166 + 167 + return 0; 168 + } 169 + 170 + static int regwindow64_set(struct task_struct *target, 171 + const struct pt_regs *regs, 172 + struct reg_window *wbuf) 173 + { 174 + unsigned long rw_addr = regs->u_regs[UREG_I6]; 175 + 176 + if (test_tsk_thread_flag(current, TIF_32BIT)) { 177 + struct reg_window32 win32; 178 + int i; 179 + 180 + for (i = 0; i < 8; i++) 181 + win32.locals[i] = wbuf->locals[i]; 182 + for (i = 0; i < 8; i++) 183 + win32.ins[i] = wbuf->ins[i]; 184 + 185 + if (set_to_target(target, rw_addr, &win32, sizeof(win32))) 186 + return -EFAULT; 187 + } else { 188 + rw_addr += STACK_BIAS; 189 + if (set_to_target(target, rw_addr, wbuf, sizeof(*wbuf))) 190 + return -EFAULT; 191 + } 192 + 193 + return 0; 194 + } 195 + 196 enum sparc_regset { 197 REGSET_GENERAL, 198 REGSET_FP, ··· 133 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 134 regs->u_regs, 135 0, 16 * sizeof(u64)); 136 + if (!ret && count && pos < (32 * sizeof(u64))) { 137 + struct reg_window window; 138 139 + if (regwindow64_get(target, regs, &window)) 140 + return -EFAULT; 141 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 142 + &window, 143 16 * sizeof(u64), 144 32 * sizeof(u64)); 145 } ··· 173 36 * sizeof(u64)); 174 } 175 176 + if (!ret) { 177 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 178 36 * sizeof(u64), -1); 179 180 + } 181 return ret; 182 } 183 ··· 194 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 195 regs->u_regs, 196 0, 16 * sizeof(u64)); 197 + if (!ret && count && pos < (32 * sizeof(u64))) { 198 + struct reg_window window; 199 200 + if (regwindow64_get(target, regs, &window)) 201 + return -EFAULT; 202 203 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 204 + &window, 205 16 * sizeof(u64), 206 32 * sizeof(u64)); 207 + 208 + if (!ret && 209 + regwindow64_set(target, regs, &window)) 210 + return -EFAULT; 211 } 212 213 if (!ret && count > 0) { ··· 805 long compat_arch_ptrace(struct task_struct *child, compat_long_t request, 806 compat_ulong_t caddr, compat_ulong_t cdata) 807 { 808 + const struct user_regset_view *view = task_user_regset_view(current); 809 compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4]; 810 struct pt_regs32 __user *pregs; 811 struct compat_fps __user *fps; ··· 913 914 long arch_ptrace(struct task_struct *child, long request, long addr, long data) 915 { 916 + const struct user_regset_view *view = task_user_regset_view(current); 917 unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; 918 struct pt_regs __user *pregs; 919 struct fps __user *fps;