diff options
author | Christoph Hellwig <hch@lst.de> | 2006-01-08 04:02:33 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-08 23:13:51 -0500 |
commit | 6b9c7ed84837753a436415097063232422e29a35 (patch) | |
tree | 6ad59a7bebcec359e08b3a211701781db819450d | |
parent | 6b34350f490b2c8508717541ec1fd2bbaadded94 (diff) |
[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>
-rw-r--r-- | arch/alpha/kernel/ptrace.c | 24 | ||||
-rw-r--r-- | arch/ia64/ia32/sys_ia32.c | 16 | ||||
-rw-r--r-- | arch/ia64/kernel/ptrace.c | 9 | ||||
-rw-r--r-- | arch/m32r/kernel/ptrace.c | 22 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace32.c | 26 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace32.c | 28 | ||||
-rw-r--r-- | arch/s390/kernel/ptrace.c | 29 | ||||
-rw-r--r-- | arch/sparc/kernel/ptrace.c | 35 | ||||
-rw-r--r-- | arch/sparc64/kernel/ptrace.c | 34 | ||||
-rw-r--r-- | arch/x86_64/ia32/ptrace32.c | 44 | ||||
-rw-r--r-- | include/linux/ptrace.h | 2 | ||||
-rw-r--r-- | kernel/ptrace.c | 77 |
12 files changed, 105 insertions, 241 deletions
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index bbd37536d14e..9969d212e94d 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c | |||
@@ -265,30 +265,16 @@ do_sys_ptrace(long request, long pid, long addr, long data, | |||
265 | lock_kernel(); | 265 | lock_kernel(); |
266 | DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n", | 266 | DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n", |
267 | request, pid, addr, data)); | 267 | request, pid, addr, data)); |
268 | ret = -EPERM; | ||
269 | if (request == PTRACE_TRACEME) { | 268 | if (request == PTRACE_TRACEME) { |
270 | /* are we already being traced? */ | 269 | ret = ptrace_traceme(); |
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; | ||
279 | goto out_notsk; | 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; | 273 | child = ptrace_get_task_struct(pid); |
285 | read_lock(&tasklist_lock); | 274 | if (IS_ERR(child)) { |
286 | child = find_task_by_pid(pid); | 275 | ret = PTR_ERR(child); |
287 | if (child) | ||
288 | get_task_struct(child); | ||
289 | read_unlock(&tasklist_lock); | ||
290 | if (!child) | ||
291 | goto out_notsk; | 276 | goto out_notsk; |
277 | } | ||
292 | 278 | ||
293 | if (request == PTRACE_ATTACH) { | 279 | if (request == PTRACE_ATTACH) { |
294 | ret = ptrace_attach(child); | 280 | ret = ptrace_attach(child); |
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index dc282710421a..9f8e8d558873 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c | |||
@@ -1761,21 +1761,15 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data) | |||
1761 | 1761 | ||
1762 | lock_kernel(); | 1762 | lock_kernel(); |
1763 | if (request == PTRACE_TRACEME) { | 1763 | if (request == PTRACE_TRACEME) { |
1764 | ret = sys_ptrace(request, pid, addr, data); | 1764 | ret = ptrace_traceme(); |
1765 | goto out; | 1765 | goto out; |
1766 | } | 1766 | } |
1767 | 1767 | ||
1768 | ret = -ESRCH; | 1768 | child = ptrace_get_task_struct(pid); |
1769 | read_lock(&tasklist_lock); | 1769 | if (IS_ERR(child)) { |
1770 | child = find_task_by_pid(pid); | 1770 | ret = PTR_ERR(child); |
1771 | if (child) | ||
1772 | get_task_struct(child); | ||
1773 | read_unlock(&tasklist_lock); | ||
1774 | if (!child) | ||
1775 | goto out; | 1771 | goto out; |
1776 | ret = -EPERM; | 1772 | } |
1777 | if (pid == 1) /* no messing around with init! */ | ||
1778 | goto out_tsk; | ||
1779 | 1773 | ||
1780 | if (request == PTRACE_ATTACH) { | 1774 | if (request == PTRACE_ATTACH) { |
1781 | ret = sys_ptrace(request, pid, addr, data); | 1775 | ret = sys_ptrace(request, pid, addr, data); |
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 4b19d0410632..8d88eeea02d1 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c | |||
@@ -1422,14 +1422,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data) | |||
1422 | lock_kernel(); | 1422 | lock_kernel(); |
1423 | ret = -EPERM; | 1423 | ret = -EPERM; |
1424 | if (request == PTRACE_TRACEME) { | 1424 | if (request == PTRACE_TRACEME) { |
1425 | /* are we already being traced? */ | 1425 | ret = ptrace_traceme(); |
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; | ||
1433 | goto out; | 1426 | goto out; |
1434 | } | 1427 | } |
1435 | 1428 | ||
diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c index 078d2a0e71c2..9b75caaf5cec 100644 --- a/arch/m32r/kernel/ptrace.c +++ b/arch/m32r/kernel/ptrace.c | |||
@@ -762,28 +762,16 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) | |||
762 | int ret; | 762 | int ret; |
763 | 763 | ||
764 | lock_kernel(); | 764 | lock_kernel(); |
765 | ret = -EPERM; | ||
766 | if (request == PTRACE_TRACEME) { | 765 | if (request == PTRACE_TRACEME) { |
767 | /* are we already being traced? */ | 766 | ret = ptrace_traceme(); |
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; | ||
773 | goto out; | 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; | 770 | child = ptrace_get_task_struct(pid); |
785 | if (pid == 1) /* you may not mess with init */ | 771 | if (IS_ERR(child)) { |
772 | ret = PTR_ERR(child); | ||
786 | goto out; | 773 | goto out; |
774 | } | ||
787 | 775 | ||
788 | if (request == PTRACE_ATTACH) { | 776 | if (request == PTRACE_ATTACH) { |
789 | ret = ptrace_attach(child); | 777 | ret = ptrace_attach(child); |
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index 9a9b04972132..7e55457a491f 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c | |||
@@ -57,30 +57,16 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) | |||
57 | (unsigned long) data); | 57 | (unsigned long) data); |
58 | #endif | 58 | #endif |
59 | lock_kernel(); | 59 | lock_kernel(); |
60 | ret = -EPERM; | ||
61 | if (request == PTRACE_TRACEME) { | 60 | if (request == PTRACE_TRACEME) { |
62 | /* are we already being traced? */ | 61 | ret = ptrace_traceme(); |
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; | ||
70 | goto out; | 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; | 65 | child = ptrace_get_task_struct(pid); |
82 | if (pid == 1) /* you may not mess with init */ | 66 | if (IS_ERR(child)) { |
83 | goto out_tsk; | 67 | ret = PTR_ERR(child); |
68 | goto out; | ||
69 | } | ||
84 | 70 | ||
85 | if (request == PTRACE_ATTACH) { | 71 | if (request == PTRACE_ATTACH) { |
86 | ret = ptrace_attach(child); | 72 | ret = ptrace_attach(child); |
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 61762640b877..826ee3d056de 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c | |||
@@ -45,33 +45,19 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, | |||
45 | unsigned long data) | 45 | unsigned long data) |
46 | { | 46 | { |
47 | struct task_struct *child; | 47 | struct task_struct *child; |
48 | int ret = -EPERM; | 48 | int ret; |
49 | 49 | ||
50 | lock_kernel(); | 50 | lock_kernel(); |
51 | if (request == PTRACE_TRACEME) { | 51 | if (request == PTRACE_TRACEME) { |
52 | /* are we already being traced? */ | 52 | ret = ptrace_traceme(); |
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; | ||
61 | goto out; | 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; | 56 | child = ptrace_get_task_struct(pid); |
73 | if (pid == 1) /* you may not mess with init */ | 57 | if (IS_ERR(child)) { |
74 | goto out_tsk; | 58 | ret = PTR_ERR(child); |
59 | goto out; | ||
60 | } | ||
75 | 61 | ||
76 | if (request == PTRACE_ATTACH) { | 62 | if (request == PTRACE_ATTACH) { |
77 | ret = ptrace_attach(child); | 63 | ret = ptrace_attach(child); |
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 8ecda6d66de4..cc02232aa96e 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -712,35 +712,18 @@ sys_ptrace(long request, long pid, long addr, long data) | |||
712 | int ret; | 712 | int ret; |
713 | 713 | ||
714 | lock_kernel(); | 714 | lock_kernel(); |
715 | |||
716 | if (request == PTRACE_TRACEME) { | 715 | if (request == PTRACE_TRACEME) { |
717 | /* are we already being traced? */ | 716 | ret = ptrace_traceme(); |
718 | ret = -EPERM; | 717 | goto out; |
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; | ||
727 | } | 718 | } |
728 | 719 | ||
729 | ret = -EPERM; | 720 | child = ptrace_get_task_struct(pid); |
730 | if (pid == 1) /* you may not mess with init */ | 721 | if (IS_ERR(child)) { |
731 | goto out; | 722 | ret = PTR_ERR(child); |
732 | |||
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; | 723 | goto out; |
724 | } | ||
741 | 725 | ||
742 | ret = do_ptrace(child, request, addr, data); | 726 | ret = do_ptrace(child, request, addr, data); |
743 | |||
744 | put_task_struct(child); | 727 | put_task_struct(child); |
745 | out: | 728 | out: |
746 | unlock_kernel(); | 729 | unlock_kernel(); |
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index 475c4c13462c..fc470c0e9dc6 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c | |||
@@ -286,40 +286,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs) | |||
286 | s, (int) request, (int) pid, addr, data, addr2); | 286 | s, (int) request, (int) pid, addr, data, addr2); |
287 | } | 287 | } |
288 | #endif | 288 | #endif |
289 | if (request == PTRACE_TRACEME) { | ||
290 | int my_ret; | ||
291 | |||
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 | 289 | ||
303 | /* set the ptrace bit in the process flags. */ | 290 | if (request == PTRACE_TRACEME) { |
304 | current->ptrace |= PT_PTRACED; | 291 | ret = ptrace_traceme(); |
305 | pt_succ_return(regs, 0); | 292 | pt_succ_return(regs, 0); |
306 | goto out; | 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) { | 296 | child = ptrace_get_task_struct(pid); |
322 | pt_error_return(regs, ESRCH); | 297 | if (IS_ERR(child)) { |
298 | ret = PTR_ERR(child); | ||
299 | pt_error_return(regs, -ret); | ||
323 | goto out; | 300 | goto out; |
324 | } | 301 | } |
325 | 302 | ||
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 774ecbb8a031..84d3df2264cb 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c | |||
@@ -198,39 +198,15 @@ asmlinkage void do_ptrace(struct pt_regs *regs) | |||
198 | } | 198 | } |
199 | #endif | 199 | #endif |
200 | if (request == PTRACE_TRACEME) { | 200 | if (request == PTRACE_TRACEME) { |
201 | int ret; | 201 | ret = ptrace_traceme(); |
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; | ||
216 | pt_succ_return(regs, 0); | 202 | pt_succ_return(regs, 0); |
217 | goto out; | 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) { | 206 | child = ptrace_get_task_struct(pid); |
233 | pt_error_return(regs, ESRCH); | 207 | if (IS_ERR(child)) { |
208 | ret = PTR_ERR(child); | ||
209 | pt_error_return(regs, -ret); | ||
234 | goto out; | 210 | goto out; |
235 | } | 211 | } |
236 | 212 | ||
diff --git a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c index 2a925e2af390..5f4cdfa56901 100644 --- a/arch/x86_64/ia32/ptrace32.c +++ b/arch/x86_64/ia32/ptrace32.c | |||
@@ -196,36 +196,6 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val) | |||
196 | 196 | ||
197 | #undef R32 | 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 | asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) | 199 | asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) |
230 | { | 200 | { |
231 | struct task_struct *child; | 201 | struct task_struct *child; |
@@ -254,9 +224,16 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) | |||
254 | break; | 224 | break; |
255 | } | 225 | } |
256 | 226 | ||
257 | child = find_target(request, pid, &ret); | 227 | if (request == PTRACE_TRACEME) |
258 | if (!child) | 228 | return ptrace_traceme(); |
259 | return ret; | 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; | ||
260 | 237 | ||
261 | childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs)); | 238 | childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs)); |
262 | 239 | ||
@@ -373,6 +350,7 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) | |||
373 | break; | 350 | break; |
374 | } | 351 | } |
375 | 352 | ||
353 | out: | ||
376 | put_task_struct(child); | 354 | put_task_struct(child); |
377 | return ret; | 355 | return ret; |
378 | } | 356 | } |
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index b2b3dba1298d..864791996b5f 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
@@ -80,6 +80,8 @@ | |||
80 | 80 | ||
81 | 81 | ||
82 | extern long arch_ptrace(struct task_struct *child, long request, long addr, long data); | 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 | extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len); | 85 | extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len); |
84 | extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); | 86 | extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); |
85 | extern int ptrace_attach(struct task_struct *tsk); | 87 | extern int ptrace_attach(struct task_struct *tsk); |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 656476eedb1b..cceaf09ac413 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -408,54 +408,62 @@ int ptrace_request(struct task_struct *child, long request, | |||
408 | return ret; | 408 | return ret; |
409 | } | 409 | } |
410 | 410 | ||
411 | #ifndef __ARCH_SYS_PTRACE | 411 | /** |
412 | static int ptrace_get_task_struct(long request, long pid, | 412 | * ptrace_traceme -- helper for PTRACE_TRACEME |
413 | struct task_struct **childp) | 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 | int ret; | 419 | int ret; |
417 | 420 | ||
418 | /* | 421 | /* |
419 | * Callers use child == NULL as an indication to exit early even | 422 | * Are we already being traced? |
420 | * when the return value is 0, so make sure it is non-NULL here. | 423 | */ |
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. | ||
421 | */ | 431 | */ |
422 | *childp = NULL; | 432 | current->ptrace |= PT_PTRACED; |
433 | return 0; | ||
434 | } | ||
423 | 435 | ||
424 | if (request == PTRACE_TRACEME) { | 436 | /** |
425 | /* | 437 | * ptrace_get_task_struct -- grab a task struct reference for ptrace |
426 | * Are we already being traced? | 438 | * @pid: process id to grab a task_struct reference of |
427 | */ | 439 | * |
428 | if (current->ptrace & PT_PTRACED) | 440 | * This function is a helper for ptrace implementations. It checks |
429 | return -EPERM; | 441 | * permissions and then grabs a task struct for use of the actual |
430 | ret = security_ptrace(current->parent, current); | 442 | * ptrace implementation. |
431 | if (ret) | 443 | * |
432 | return -EPERM; | 444 | * Returns the task_struct for @pid or an ERR_PTR() on failure. |
433 | /* | 445 | */ |
434 | * Set the ptrace bit in the process ptrace flags. | 446 | struct task_struct *ptrace_get_task_struct(pid_t pid) |
435 | */ | 447 | { |
436 | current->ptrace |= PT_PTRACED; | 448 | struct task_struct *child; |
437 | return 0; | ||
438 | } | ||
439 | 449 | ||
440 | /* | 450 | /* |
441 | * You may not mess with init | 451 | * Tracing init is not allowed. |
442 | */ | 452 | */ |
443 | if (pid == 1) | 453 | if (pid == 1) |
444 | return -EPERM; | 454 | return ERR_PTR(-EPERM); |
445 | 455 | ||
446 | ret = -ESRCH; | ||
447 | read_lock(&tasklist_lock); | 456 | read_lock(&tasklist_lock); |
448 | child = find_task_by_pid(pid); | 457 | child = find_task_by_pid(pid); |
449 | if (child) | 458 | if (child) |
450 | get_task_struct(child); | 459 | get_task_struct(child); |
451 | read_unlock(&tasklist_lock); | 460 | read_unlock(&tasklist_lock); |
452 | if (!child) | 461 | if (!child) |
453 | return -ESRCH; | 462 | return ERR_PTR(-ESRCH); |
454 | 463 | return child; | |
455 | *childp = child; | ||
456 | return 0; | ||
457 | } | 464 | } |
458 | 465 | ||
466 | #ifndef __ARCH_SYS_PTRACE | ||
459 | asmlinkage long sys_ptrace(long request, long pid, long addr, long data) | 467 | asmlinkage long sys_ptrace(long request, long pid, long addr, long data) |
460 | { | 468 | { |
461 | struct task_struct *child; | 469 | struct task_struct *child; |
@@ -465,9 +473,16 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) | |||
465 | * This lock_kernel fixes a subtle race with suid exec | 473 | * This lock_kernel fixes a subtle race with suid exec |
466 | */ | 474 | */ |
467 | lock_kernel(); | 475 | lock_kernel(); |
468 | ret = ptrace_get_task_struct(request, pid, &child); | 476 | if (request == PTRACE_TRACEME) { |
469 | if (!child) | 477 | ret = ptrace_traceme(); |
470 | goto out; | 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 | if (request == PTRACE_ATTACH) { | 487 | if (request == PTRACE_ATTACH) { |
473 | ret = ptrace_attach(child); | 488 | ret = ptrace_attach(child); |