diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-10-15 07:46:29 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-15 07:46:29 -0400 |
commit | b2aaf8f74cdc84a9182f6cabf198b7763bcb9d40 (patch) | |
tree | 53ccb1c2c14751fe69cf93102e76e97021f6df07 /kernel/ptrace.c | |
parent | 4f962d4d65923d7b722192e729840cfb79af0a5a (diff) | |
parent | 278429cff8809958d25415ba0ed32b59866ab1a8 (diff) |
Merge branch 'linus' into stackprotector
Conflicts:
arch/x86/kernel/Makefile
include/asm-x86/pda.h
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r-- | kernel/ptrace.c | 53 |
1 files changed, 32 insertions, 21 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 6c19e94fd0a5..356699a96d56 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -33,13 +33,9 @@ | |||
33 | */ | 33 | */ |
34 | void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) | 34 | void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) |
35 | { | 35 | { |
36 | BUG_ON(!list_empty(&child->ptrace_list)); | 36 | BUG_ON(!list_empty(&child->ptrace_entry)); |
37 | if (child->parent == new_parent) | 37 | list_add(&child->ptrace_entry, &new_parent->ptraced); |
38 | return; | ||
39 | list_add(&child->ptrace_list, &child->parent->ptrace_children); | ||
40 | remove_parent(child); | ||
41 | child->parent = new_parent; | 38 | child->parent = new_parent; |
42 | add_parent(child); | ||
43 | } | 39 | } |
44 | 40 | ||
45 | /* | 41 | /* |
@@ -73,12 +69,8 @@ void __ptrace_unlink(struct task_struct *child) | |||
73 | BUG_ON(!child->ptrace); | 69 | BUG_ON(!child->ptrace); |
74 | 70 | ||
75 | child->ptrace = 0; | 71 | child->ptrace = 0; |
76 | if (ptrace_reparented(child)) { | 72 | child->parent = child->real_parent; |
77 | list_del_init(&child->ptrace_list); | 73 | list_del_init(&child->ptrace_entry); |
78 | remove_parent(child); | ||
79 | child->parent = child->real_parent; | ||
80 | add_parent(child); | ||
81 | } | ||
82 | 74 | ||
83 | if (task_is_traced(child)) | 75 | if (task_is_traced(child)) |
84 | ptrace_untrace(child); | 76 | ptrace_untrace(child); |
@@ -115,13 +107,13 @@ int ptrace_check_attach(struct task_struct *child, int kill) | |||
115 | read_unlock(&tasklist_lock); | 107 | read_unlock(&tasklist_lock); |
116 | 108 | ||
117 | if (!ret && !kill) | 109 | if (!ret && !kill) |
118 | wait_task_inactive(child); | 110 | ret = wait_task_inactive(child, TASK_TRACED) ? 0 : -ESRCH; |
119 | 111 | ||
120 | /* All systems go.. */ | 112 | /* All systems go.. */ |
121 | return ret; | 113 | return ret; |
122 | } | 114 | } |
123 | 115 | ||
124 | int __ptrace_may_attach(struct task_struct *task) | 116 | int __ptrace_may_access(struct task_struct *task, unsigned int mode) |
125 | { | 117 | { |
126 | /* May we inspect the given task? | 118 | /* May we inspect the given task? |
127 | * This check is used both for attaching with ptrace | 119 | * This check is used both for attaching with ptrace |
@@ -148,16 +140,16 @@ int __ptrace_may_attach(struct task_struct *task) | |||
148 | if (!dumpable && !capable(CAP_SYS_PTRACE)) | 140 | if (!dumpable && !capable(CAP_SYS_PTRACE)) |
149 | return -EPERM; | 141 | return -EPERM; |
150 | 142 | ||
151 | return security_ptrace(current, task); | 143 | return security_ptrace_may_access(task, mode); |
152 | } | 144 | } |
153 | 145 | ||
154 | int ptrace_may_attach(struct task_struct *task) | 146 | bool ptrace_may_access(struct task_struct *task, unsigned int mode) |
155 | { | 147 | { |
156 | int err; | 148 | int err; |
157 | task_lock(task); | 149 | task_lock(task); |
158 | err = __ptrace_may_attach(task); | 150 | err = __ptrace_may_access(task, mode); |
159 | task_unlock(task); | 151 | task_unlock(task); |
160 | return !err; | 152 | return (!err ? true : false); |
161 | } | 153 | } |
162 | 154 | ||
163 | int ptrace_attach(struct task_struct *task) | 155 | int ptrace_attach(struct task_struct *task) |
@@ -195,7 +187,7 @@ repeat: | |||
195 | /* the same process cannot be attached many times */ | 187 | /* the same process cannot be attached many times */ |
196 | if (task->ptrace & PT_PTRACED) | 188 | if (task->ptrace & PT_PTRACED) |
197 | goto bad; | 189 | goto bad; |
198 | retval = __ptrace_may_attach(task); | 190 | retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); |
199 | if (retval) | 191 | if (retval) |
200 | goto bad; | 192 | goto bad; |
201 | 193 | ||
@@ -492,14 +484,33 @@ int ptrace_traceme(void) | |||
492 | /* | 484 | /* |
493 | * Are we already being traced? | 485 | * Are we already being traced? |
494 | */ | 486 | */ |
487 | repeat: | ||
495 | task_lock(current); | 488 | task_lock(current); |
496 | if (!(current->ptrace & PT_PTRACED)) { | 489 | if (!(current->ptrace & PT_PTRACED)) { |
497 | ret = security_ptrace(current->parent, current); | 490 | /* |
491 | * See ptrace_attach() comments about the locking here. | ||
492 | */ | ||
493 | unsigned long flags; | ||
494 | if (!write_trylock_irqsave(&tasklist_lock, flags)) { | ||
495 | task_unlock(current); | ||
496 | do { | ||
497 | cpu_relax(); | ||
498 | } while (!write_can_lock(&tasklist_lock)); | ||
499 | goto repeat; | ||
500 | } | ||
501 | |||
502 | ret = security_ptrace_traceme(current->parent); | ||
503 | |||
498 | /* | 504 | /* |
499 | * Set the ptrace bit in the process ptrace flags. | 505 | * Set the ptrace bit in the process ptrace flags. |
506 | * Then link us on our parent's ptraced list. | ||
500 | */ | 507 | */ |
501 | if (!ret) | 508 | if (!ret) { |
502 | current->ptrace |= PT_PTRACED; | 509 | current->ptrace |= PT_PTRACED; |
510 | __ptrace_link(current, current->real_parent); | ||
511 | } | ||
512 | |||
513 | write_unlock_irqrestore(&tasklist_lock, flags); | ||
503 | } | 514 | } |
504 | task_unlock(current); | 515 | task_unlock(current); |
505 | return ret; | 516 | return ret; |