Commit 6b9c7ed84837753a436415097063232422e29a35

Authored by Christoph Hellwig
Committed by Linus Torvalds
1 parent 6b34350f49

[PATCH] use ptrace_get_task_struct in various places

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 <hch@lst.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 12 changed files with 105 additions and 241 deletions Side-by-side Diff

arch/alpha/kernel/ptrace.c
... ... @@ -265,30 +265,16 @@
265 265 lock_kernel();
266 266 DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",
267 267 request, pid, addr, data));
268   - ret = -EPERM;
269 268 if (request == PTRACE_TRACEME) {
270   - /* are we already being traced? */
271   - if (current->ptrace & PT_PTRACED)
272   - goto out_notsk;
273   - ret = security_ptrace(current->parent, current);
274   - if (ret)
275   - goto out_notsk;
276   - /* set the ptrace bit in the process ptrace flags. */
277   - current->ptrace |= PT_PTRACED;
278   - ret = 0;
  269 + ret = ptrace_traceme();
279 270 goto out_notsk;
280 271 }
281   - if (pid == 1) /* you may not mess with init */
282   - goto out_notsk;
283 272  
284   - ret = -ESRCH;
285   - read_lock(&tasklist_lock);
286   - child = find_task_by_pid(pid);
287   - if (child)
288   - get_task_struct(child);
289   - read_unlock(&tasklist_lock);
290   - if (!child)
  273 + child = ptrace_get_task_struct(pid);
  274 + if (IS_ERR(child)) {
  275 + ret = PTR_ERR(child);
291 276 goto out_notsk;
  277 + }
292 278  
293 279 if (request == PTRACE_ATTACH) {
294 280 ret = ptrace_attach(child);
arch/ia64/ia32/sys_ia32.c
... ... @@ -1761,21 +1761,15 @@
1761 1761  
1762 1762 lock_kernel();
1763 1763 if (request == PTRACE_TRACEME) {
1764   - ret = sys_ptrace(request, pid, addr, data);
  1764 + ret = ptrace_traceme();
1765 1765 goto out;
1766 1766 }
1767 1767  
1768   - ret = -ESRCH;
1769   - read_lock(&tasklist_lock);
1770   - child = find_task_by_pid(pid);
1771   - if (child)
1772   - get_task_struct(child);
1773   - read_unlock(&tasklist_lock);
1774   - if (!child)
  1768 + child = ptrace_get_task_struct(pid);
  1769 + if (IS_ERR(child)) {
  1770 + ret = PTR_ERR(child);
1775 1771 goto out;
1776   - ret = -EPERM;
1777   - if (pid == 1) /* no messing around with init! */
1778   - goto out_tsk;
  1772 + }
1779 1773  
1780 1774 if (request == PTRACE_ATTACH) {
1781 1775 ret = sys_ptrace(request, pid, addr, data);
arch/ia64/kernel/ptrace.c
... ... @@ -1422,14 +1422,7 @@
1422 1422 lock_kernel();
1423 1423 ret = -EPERM;
1424 1424 if (request == PTRACE_TRACEME) {
1425   - /* are we already being traced? */
1426   - if (current->ptrace & PT_PTRACED)
1427   - goto out;
1428   - ret = security_ptrace(current->parent, current);
1429   - if (ret)
1430   - goto out;
1431   - current->ptrace |= PT_PTRACED;
1432   - ret = 0;
  1425 + ret = ptrace_traceme();
1433 1426 goto out;
1434 1427 }
1435 1428  
arch/m32r/kernel/ptrace.c
... ... @@ -762,28 +762,16 @@
762 762 int ret;
763 763  
764 764 lock_kernel();
765   - ret = -EPERM;
766 765 if (request == PTRACE_TRACEME) {
767   - /* are we already being traced? */
768   - if (current->ptrace & PT_PTRACED)
769   - goto out;
770   - /* set the ptrace bit in the process flags. */
771   - current->ptrace |= PT_PTRACED;
772   - ret = 0;
  766 + ret = ptrace_traceme();
773 767 goto out;
774 768 }
775   - ret = -ESRCH;
776   - read_lock(&tasklist_lock);
777   - child = find_task_by_pid(pid);
778   - if (child)
779   - get_task_struct(child);
780   - read_unlock(&tasklist_lock);
781   - if (!child)
782   - goto out;
783 769  
784   - ret = -EPERM;
785   - if (pid == 1) /* you may not mess with init */
  770 + child = ptrace_get_task_struct(pid);
  771 + if (IS_ERR(child)) {
  772 + ret = PTR_ERR(child);
786 773 goto out;
  774 + }
787 775  
788 776 if (request == PTRACE_ATTACH) {
789 777 ret = ptrace_attach(child);
arch/mips/kernel/ptrace32.c
... ... @@ -57,30 +57,16 @@
57 57 (unsigned long) data);
58 58 #endif
59 59 lock_kernel();
60   - ret = -EPERM;
61 60 if (request == PTRACE_TRACEME) {
62   - /* are we already being traced? */
63   - if (current->ptrace & PT_PTRACED)
64   - goto out;
65   - if ((ret = security_ptrace(current->parent, current)))
66   - goto out;
67   - /* set the ptrace bit in the process flags. */
68   - current->ptrace |= PT_PTRACED;
69   - ret = 0;
  61 + ret = ptrace_traceme();
70 62 goto out;
71 63 }
72   - ret = -ESRCH;
73   - read_lock(&tasklist_lock);
74   - child = find_task_by_pid(pid);
75   - if (child)
76   - get_task_struct(child);
77   - read_unlock(&tasklist_lock);
78   - if (!child)
79   - goto out;
80 64  
81   - ret = -EPERM;
82   - if (pid == 1) /* you may not mess with init */
83   - goto out_tsk;
  65 + child = ptrace_get_task_struct(pid);
  66 + if (IS_ERR(child)) {
  67 + ret = PTR_ERR(child);
  68 + goto out;
  69 + }
84 70  
85 71 if (request == PTRACE_ATTACH) {
86 72 ret = ptrace_attach(child);
arch/powerpc/kernel/ptrace32.c
... ... @@ -45,33 +45,19 @@
45 45 unsigned long data)
46 46 {
47 47 struct task_struct *child;
48   - int ret = -EPERM;
  48 + int ret;
49 49  
50 50 lock_kernel();
51 51 if (request == PTRACE_TRACEME) {
52   - /* are we already being traced? */
53   - if (current->ptrace & PT_PTRACED)
54   - goto out;
55   - ret = security_ptrace(current->parent, current);
56   - if (ret)
57   - goto out;
58   - /* set the ptrace bit in the process flags. */
59   - current->ptrace |= PT_PTRACED;
60   - ret = 0;
  52 + ret = ptrace_traceme();
61 53 goto out;
62 54 }
63   - ret = -ESRCH;
64   - read_lock(&tasklist_lock);
65   - child = find_task_by_pid(pid);
66   - if (child)
67   - get_task_struct(child);
68   - read_unlock(&tasklist_lock);
69   - if (!child)
70   - goto out;
71 55  
72   - ret = -EPERM;
73   - if (pid == 1) /* you may not mess with init */
74   - goto out_tsk;
  56 + child = ptrace_get_task_struct(pid);
  57 + if (IS_ERR(child)) {
  58 + ret = PTR_ERR(child);
  59 + goto out;
  60 + }
75 61  
76 62 if (request == PTRACE_ATTACH) {
77 63 ret = ptrace_attach(child);
arch/s390/kernel/ptrace.c
... ... @@ -712,35 +712,18 @@
712 712 int ret;
713 713  
714 714 lock_kernel();
715   -
716 715 if (request == PTRACE_TRACEME) {
717   - /* are we already being traced? */
718   - ret = -EPERM;
719   - if (current->ptrace & PT_PTRACED)
720   - goto out;
721   - ret = security_ptrace(current->parent, current);
722   - if (ret)
723   - goto out;
724   - /* set the ptrace bit in the process flags. */
725   - current->ptrace |= PT_PTRACED;
726   - goto out;
  716 + ret = ptrace_traceme();
  717 + goto out;
727 718 }
728 719  
729   - ret = -EPERM;
730   - if (pid == 1) /* you may not mess with init */
  720 + child = ptrace_get_task_struct(pid);
  721 + if (IS_ERR(child)) {
  722 + ret = PTR_ERR(child);
731 723 goto out;
  724 + }
732 725  
733   - ret = -ESRCH;
734   - read_lock(&tasklist_lock);
735   - child = find_task_by_pid(pid);
736   - if (child)
737   - get_task_struct(child);
738   - read_unlock(&tasklist_lock);
739   - if (!child)
740   - goto out;
741   -
742 726 ret = do_ptrace(child, request, addr, data);
743   -
744 727 put_task_struct(child);
745 728 out:
746 729 unlock_kernel();
arch/sparc/kernel/ptrace.c
... ... @@ -286,40 +286,17 @@
286 286 s, (int) request, (int) pid, addr, data, addr2);
287 287 }
288 288 #endif
289   - if (request == PTRACE_TRACEME) {
290   - int my_ret;
291 289  
292   - /* are we already being traced? */
293   - if (current->ptrace & PT_PTRACED) {
294   - pt_error_return(regs, EPERM);
295   - goto out;
296   - }
297   - my_ret = security_ptrace(current->parent, current);
298   - if (my_ret) {
299   - pt_error_return(regs, -my_ret);
300   - goto out;
301   - }
302   -
303   - /* set the ptrace bit in the process flags. */
304   - current->ptrace |= PT_PTRACED;
  290 + if (request == PTRACE_TRACEME) {
  291 + ret = ptrace_traceme();
305 292 pt_succ_return(regs, 0);
306 293 goto out;
307 294 }
308   -#ifndef ALLOW_INIT_TRACING
309   - if (pid == 1) {
310   - /* Can't dork with init. */
311   - pt_error_return(regs, EPERM);
312   - goto out;
313   - }
314   -#endif
315   - read_lock(&tasklist_lock);
316   - child = find_task_by_pid(pid);
317   - if (child)
318   - get_task_struct(child);
319   - read_unlock(&tasklist_lock);
320 295  
321   - if (!child) {
322   - pt_error_return(regs, ESRCH);
  296 + child = ptrace_get_task_struct(pid);
  297 + if (IS_ERR(child)) {
  298 + ret = PTR_ERR(child);
  299 + pt_error_return(regs, -ret);
323 300 goto out;
324 301 }
325 302  
arch/sparc64/kernel/ptrace.c
... ... @@ -198,39 +198,15 @@
198 198 }
199 199 #endif
200 200 if (request == PTRACE_TRACEME) {
201   - int ret;
202   -
203   - /* are we already being traced? */
204   - if (current->ptrace & PT_PTRACED) {
205   - pt_error_return(regs, EPERM);
206   - goto out;
207   - }
208   - ret = security_ptrace(current->parent, current);
209   - if (ret) {
210   - pt_error_return(regs, -ret);
211   - goto out;
212   - }
213   -
214   - /* set the ptrace bit in the process flags. */
215   - current->ptrace |= PT_PTRACED;
  201 + ret = ptrace_traceme();
216 202 pt_succ_return(regs, 0);
217 203 goto out;
218 204 }
219   -#ifndef ALLOW_INIT_TRACING
220   - if (pid == 1) {
221   - /* Can't dork with init. */
222   - pt_error_return(regs, EPERM);
223   - goto out;
224   - }
225   -#endif
226   - read_lock(&tasklist_lock);
227   - child = find_task_by_pid(pid);
228   - if (child)
229   - get_task_struct(child);
230   - read_unlock(&tasklist_lock);
231 205  
232   - if (!child) {
233   - pt_error_return(regs, ESRCH);
  206 + child = ptrace_get_task_struct(pid);
  207 + if (IS_ERR(child)) {
  208 + ret = PTR_ERR(child);
  209 + pt_error_return(regs, -ret);
234 210 goto out;
235 211 }
236 212  
arch/x86_64/ia32/ptrace32.c
... ... @@ -196,36 +196,6 @@
196 196  
197 197 #undef R32
198 198  
199   -static struct task_struct *find_target(int request, int pid, int *err)
200   -{
201   - struct task_struct *child;
202   -
203   - *err = -EPERM;
204   - if (pid == 1)
205   - return NULL;
206   -
207   - *err = -ESRCH;
208   - read_lock(&tasklist_lock);
209   - child = find_task_by_pid(pid);
210   - if (child)
211   - get_task_struct(child);
212   - read_unlock(&tasklist_lock);
213   - if (child) {
214   - *err = -EPERM;
215   - if (child->pid == 1)
216   - goto out;
217   - *err = ptrace_check_attach(child, request == PTRACE_KILL);
218   - if (*err < 0)
219   - goto out;
220   - return child;
221   - }
222   - out:
223   - if (child)
224   - put_task_struct(child);
225   - return NULL;
226   -
227   -}
228   -
229 199 asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
230 200 {
231 201 struct task_struct *child;
232 202  
... ... @@ -254,10 +224,17 @@
254 224 break;
255 225 }
256 226  
257   - child = find_target(request, pid, &ret);
258   - if (!child)
259   - return ret;
  227 + if (request == PTRACE_TRACEME)
  228 + return ptrace_traceme();
260 229  
  230 + child = ptrace_get_task_struct(pid);
  231 + if (IS_ERR(child))
  232 + return PTR_ERR(child);
  233 +
  234 + ret = ptrace_check_attach(child, request == PTRACE_KILL);
  235 + if (ret < 0)
  236 + goto out;
  237 +
261 238 childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs));
262 239  
263 240 switch (request) {
... ... @@ -373,6 +350,7 @@
373 350 break;
374 351 }
375 352  
  353 + out:
376 354 put_task_struct(child);
377 355 return ret;
378 356 }
include/linux/ptrace.h
... ... @@ -80,6 +80,8 @@
80 80  
81 81  
82 82 extern long arch_ptrace(struct task_struct *child, long request, long addr, long data);
  83 +extern struct task_struct *ptrace_get_task_struct(pid_t pid);
  84 +extern int ptrace_traceme(void);
83 85 extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
84 86 extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len);
85 87 extern int ptrace_attach(struct task_struct *tsk);
... ... @@ -408,54 +408,62 @@
408 408 return ret;
409 409 }
410 410  
411   -#ifndef __ARCH_SYS_PTRACE
412   -static int ptrace_get_task_struct(long request, long pid,
413   - struct task_struct **childp)
  411 +/**
  412 + * ptrace_traceme -- helper for PTRACE_TRACEME
  413 + *
  414 + * Performs checks and sets PT_PTRACED.
  415 + * Should be used by all ptrace implementations for PTRACE_TRACEME.
  416 + */
  417 +int ptrace_traceme(void)
414 418 {
415   - struct task_struct *child;
416 419 int ret;
417 420  
418 421 /*
419   - * Callers use child == NULL as an indication to exit early even
420   - * when the return value is 0, so make sure it is non-NULL here.
  422 + * Are we already being traced?
421 423 */
422   - *childp = NULL;
  424 + if (current->ptrace & PT_PTRACED)
  425 + return -EPERM;
  426 + ret = security_ptrace(current->parent, current);
  427 + if (ret)
  428 + return -EPERM;
  429 + /*
  430 + * Set the ptrace bit in the process ptrace flags.
  431 + */
  432 + current->ptrace |= PT_PTRACED;
  433 + return 0;
  434 +}
423 435  
424   - if (request == PTRACE_TRACEME) {
425   - /*
426   - * Are we already being traced?
427   - */
428   - if (current->ptrace & PT_PTRACED)
429   - return -EPERM;
430   - ret = security_ptrace(current->parent, current);
431   - if (ret)
432   - return -EPERM;
433   - /*
434   - * Set the ptrace bit in the process ptrace flags.
435   - */
436   - current->ptrace |= PT_PTRACED;
437   - return 0;
438   - }
  436 +/**
  437 + * ptrace_get_task_struct -- grab a task struct reference for ptrace
  438 + * @pid: process id to grab a task_struct reference of
  439 + *
  440 + * This function is a helper for ptrace implementations. It checks
  441 + * permissions and then grabs a task struct for use of the actual
  442 + * ptrace implementation.
  443 + *
  444 + * Returns the task_struct for @pid or an ERR_PTR() on failure.
  445 + */
  446 +struct task_struct *ptrace_get_task_struct(pid_t pid)
  447 +{
  448 + struct task_struct *child;
439 449  
440 450 /*
441   - * You may not mess with init
  451 + * Tracing init is not allowed.
442 452 */
443 453 if (pid == 1)
444   - return -EPERM;
  454 + return ERR_PTR(-EPERM);
445 455  
446   - ret = -ESRCH;
447 456 read_lock(&tasklist_lock);
448 457 child = find_task_by_pid(pid);
449 458 if (child)
450 459 get_task_struct(child);
451 460 read_unlock(&tasklist_lock);
452 461 if (!child)
453   - return -ESRCH;
454   -
455   - *childp = child;
456   - return 0;
  462 + return ERR_PTR(-ESRCH);
  463 + return child;
457 464 }
458 465  
  466 +#ifndef __ARCH_SYS_PTRACE
459 467 asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
460 468 {
461 469 struct task_struct *child;
462 470  
... ... @@ -465,9 +473,16 @@
465 473 * This lock_kernel fixes a subtle race with suid exec
466 474 */
467 475 lock_kernel();
468   - ret = ptrace_get_task_struct(request, pid, &child);
469   - if (!child)
  476 + if (request == PTRACE_TRACEME) {
  477 + ret = ptrace_traceme();
470 478 goto out;
  479 + }
  480 +
  481 + child = ptrace_get_task_struct(pid);
  482 + if (IS_ERR(child)) {
  483 + ret = PTR_ERR(child);
  484 + goto out;
  485 + }
471 486  
472 487 if (request == PTRACE_ATTACH) {
473 488 ret = ptrace_attach(child);