aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2009-06-17 19:27:32 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-18 16:03:51 -0400
commitf2f0b00ad61d53adfecb8bdf8f3cf8f05f6ed548 (patch)
treedda08f8bb3e8c403b2d1cf941b17c9909975c209
parentb79b7ba93df14a1fc0b8d4d6d78a0e097de03bbd (diff)
ptrace: cleanup check/set of PT_PTRACED during attach
ptrace_attach() and ptrace_traceme() are the last functions which look as if the untraced task can have task->ptrace != 0, this must not be possible. Change the code to just check ->ptrace != 0 and s/|=/=/ to set PT_PTRACED. Also, a couple of trivial whitespace cleanups in ptrace_attach(). And move ptrace_traceme() up near ptrace_attach() to keep them close to each other. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Cc: Chris Wright <chrisw@sous-sol.org> Acked-by: Roland McGrath <roland@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--kernel/ptrace.c101
1 files changed, 51 insertions, 50 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 9439bd3331a6..12e21a949db1 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -177,12 +177,13 @@ int ptrace_attach(struct task_struct *task)
177 if (same_thread_group(task, current)) 177 if (same_thread_group(task, current))
178 goto out; 178 goto out;
179 179
180 /* Protect the target's credential calculations against our 180 /*
181 * Protect exec's credential calculations against our interference;
181 * interference; SUID, SGID and LSM creds get determined differently 182 * interference; SUID, SGID and LSM creds get determined differently
182 * under ptrace. 183 * under ptrace.
183 */ 184 */
184 retval = mutex_lock_interruptible(&task->cred_guard_mutex); 185 retval = mutex_lock_interruptible(&task->cred_guard_mutex);
185 if (retval < 0) 186 if (retval < 0)
186 goto out; 187 goto out;
187repeat: 188repeat:
188 /* 189 /*
@@ -210,10 +211,10 @@ repeat:
210 retval = -EPERM; 211 retval = -EPERM;
211 if (unlikely(task->exit_state)) 212 if (unlikely(task->exit_state))
212 goto bad; 213 goto bad;
213 if (task->ptrace & PT_PTRACED) 214 if (task->ptrace)
214 goto bad; 215 goto bad;
215 216
216 task->ptrace |= PT_PTRACED; 217 task->ptrace = PT_PTRACED;
217 if (capable(CAP_SYS_PTRACE)) 218 if (capable(CAP_SYS_PTRACE))
218 task->ptrace |= PT_PTRACE_CAP; 219 task->ptrace |= PT_PTRACE_CAP;
219 220
@@ -229,6 +230,52 @@ out:
229 return retval; 230 return retval;
230} 231}
231 232
233/**
234 * ptrace_traceme -- helper for PTRACE_TRACEME
235 *
236 * Performs checks and sets PT_PTRACED.
237 * Should be used by all ptrace implementations for PTRACE_TRACEME.
238 */
239int ptrace_traceme(void)
240{
241 int ret = -EPERM;
242
243 /*
244 * Are we already being traced?
245 */
246repeat:
247 task_lock(current);
248 if (!current->ptrace) {
249 /*
250 * See ptrace_attach() comments about the locking here.
251 */
252 unsigned long flags;
253 if (!write_trylock_irqsave(&tasklist_lock, flags)) {
254 task_unlock(current);
255 do {
256 cpu_relax();
257 } while (!write_can_lock(&tasklist_lock));
258 goto repeat;
259 }
260
261 ret = security_ptrace_traceme(current->parent);
262
263 /*
264 * Check PF_EXITING to ensure ->real_parent has not passed
265 * exit_ptrace(). Otherwise we don't report the error but
266 * pretend ->real_parent untraces us right after return.
267 */
268 if (!ret && !(current->real_parent->flags & PF_EXITING)) {
269 current->ptrace = PT_PTRACED;
270 __ptrace_link(current, current->real_parent);
271 }
272
273 write_unlock_irqrestore(&tasklist_lock, flags);
274 }
275 task_unlock(current);
276 return ret;
277}
278
232/* 279/*
233 * Called with irqs disabled, returns true if childs should reap themselves. 280 * Called with irqs disabled, returns true if childs should reap themselves.
234 */ 281 */
@@ -568,52 +615,6 @@ int ptrace_request(struct task_struct *child, long request,
568} 615}
569 616
570/** 617/**
571 * ptrace_traceme -- helper for PTRACE_TRACEME
572 *
573 * Performs checks and sets PT_PTRACED.
574 * Should be used by all ptrace implementations for PTRACE_TRACEME.
575 */
576int ptrace_traceme(void)
577{
578 int ret = -EPERM;
579
580 /*
581 * Are we already being traced?
582 */
583repeat:
584 task_lock(current);
585 if (!(current->ptrace & PT_PTRACED)) {
586 /*
587 * See ptrace_attach() comments about the locking here.
588 */
589 unsigned long flags;
590 if (!write_trylock_irqsave(&tasklist_lock, flags)) {
591 task_unlock(current);
592 do {
593 cpu_relax();
594 } while (!write_can_lock(&tasklist_lock));
595 goto repeat;
596 }
597
598 ret = security_ptrace_traceme(current->parent);
599
600 /*
601 * Check PF_EXITING to ensure ->real_parent has not passed
602 * exit_ptrace(). Otherwise we don't report the error but
603 * pretend ->real_parent untraces us right after return.
604 */
605 if (!ret && !(current->real_parent->flags & PF_EXITING)) {
606 current->ptrace |= PT_PTRACED;
607 __ptrace_link(current, current->real_parent);
608 }
609
610 write_unlock_irqrestore(&tasklist_lock, flags);
611 }
612 task_unlock(current);
613 return ret;
614}
615
616/**
617 * ptrace_get_task_struct -- grab a task struct reference for ptrace 618 * ptrace_get_task_struct -- grab a task struct reference for ptrace
618 * @pid: process id to grab a task_struct reference of 619 * @pid: process id to grab a task_struct reference of
619 * 620 *