aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r--kernel/ptrace.c77
1 files changed, 46 insertions, 31 deletions
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/**
412static 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 */
417int 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. 446struct 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
459asmlinkage long sys_ptrace(long request, long pid, long addr, long data) 467asmlinkage 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);