Commit 6b9c7ed84837753a436415097063232422e29a35
Committed by
Linus Torvalds
1 parent
6b34350f49
Exists in
master
and in
7 other branches
[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
- arch/ia64/ia32/sys_ia32.c
- arch/ia64/kernel/ptrace.c
- arch/m32r/kernel/ptrace.c
- arch/mips/kernel/ptrace32.c
- arch/powerpc/kernel/ptrace32.c
- arch/s390/kernel/ptrace.c
- arch/sparc/kernel/ptrace.c
- arch/sparc64/kernel/ptrace.c
- arch/x86_64/ia32/ptrace32.c
- include/linux/ptrace.h
- kernel/ptrace.c
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); |
kernel/ptrace.c
... | ... | @@ -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); |