aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r--kernel/ptrace.c78
1 files changed, 47 insertions, 31 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 656476eedb1b..5f33cdb6fff5 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -7,6 +7,7 @@
7 * to continually duplicate across every architecture. 7 * to continually duplicate across every architecture.
8 */ 8 */
9 9
10#include <linux/capability.h>
10#include <linux/module.h> 11#include <linux/module.h>
11#include <linux/sched.h> 12#include <linux/sched.h>
12#include <linux/errno.h> 13#include <linux/errno.h>
@@ -408,54 +409,62 @@ int ptrace_request(struct task_struct *child, long request,
408 return ret; 409 return ret;
409} 410}
410 411
411#ifndef __ARCH_SYS_PTRACE 412/**
412static int ptrace_get_task_struct(long request, long pid, 413 * ptrace_traceme -- helper for PTRACE_TRACEME
413 struct task_struct **childp) 414 *
415 * Performs checks and sets PT_PTRACED.
416 * Should be used by all ptrace implementations for PTRACE_TRACEME.
417 */
418int ptrace_traceme(void)
414{ 419{
415 struct task_struct *child;
416 int ret; 420 int ret;
417 421
418 /* 422 /*
419 * Callers use child == NULL as an indication to exit early even 423 * Are we already being traced?
420 * when the return value is 0, so make sure it is non-NULL here. 424 */
425 if (current->ptrace & PT_PTRACED)
426 return -EPERM;
427 ret = security_ptrace(current->parent, current);
428 if (ret)
429 return -EPERM;
430 /*
431 * Set the ptrace bit in the process ptrace flags.
421 */ 432 */
422 *childp = NULL; 433 current->ptrace |= PT_PTRACED;
434 return 0;
435}
423 436
424 if (request == PTRACE_TRACEME) { 437/**
425 /* 438 * ptrace_get_task_struct -- grab a task struct reference for ptrace
426 * Are we already being traced? 439 * @pid: process id to grab a task_struct reference of
427 */ 440 *
428 if (current->ptrace & PT_PTRACED) 441 * This function is a helper for ptrace implementations. It checks
429 return -EPERM; 442 * permissions and then grabs a task struct for use of the actual
430 ret = security_ptrace(current->parent, current); 443 * ptrace implementation.
431 if (ret) 444 *
432 return -EPERM; 445 * Returns the task_struct for @pid or an ERR_PTR() on failure.
433 /* 446 */
434 * Set the ptrace bit in the process ptrace flags. 447struct task_struct *ptrace_get_task_struct(pid_t pid)
435 */ 448{
436 current->ptrace |= PT_PTRACED; 449 struct task_struct *child;
437 return 0;
438 }
439 450
440 /* 451 /*
441 * You may not mess with init 452 * Tracing init is not allowed.
442 */ 453 */
443 if (pid == 1) 454 if (pid == 1)
444 return -EPERM; 455 return ERR_PTR(-EPERM);
445 456
446 ret = -ESRCH;
447 read_lock(&tasklist_lock); 457 read_lock(&tasklist_lock);
448 child = find_task_by_pid(pid); 458 child = find_task_by_pid(pid);
449 if (child) 459 if (child)
450 get_task_struct(child); 460 get_task_struct(child);
451 read_unlock(&tasklist_lock); 461 read_unlock(&tasklist_lock);
452 if (!child) 462 if (!child)
453 return -ESRCH; 463 return ERR_PTR(-ESRCH);
454 464 return child;
455 *childp = child;
456 return 0;
457} 465}
458 466
467#ifndef __ARCH_SYS_PTRACE
459asmlinkage long sys_ptrace(long request, long pid, long addr, long data) 468asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
460{ 469{
461 struct task_struct *child; 470 struct task_struct *child;
@@ -465,9 +474,16 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
465 * This lock_kernel fixes a subtle race with suid exec 474 * This lock_kernel fixes a subtle race with suid exec
466 */ 475 */
467 lock_kernel(); 476 lock_kernel();
468 ret = ptrace_get_task_struct(request, pid, &child); 477 if (request == PTRACE_TRACEME) {
469 if (!child) 478 ret = ptrace_traceme();
470 goto out; 479 goto out;
480 }
481
482 child = ptrace_get_task_struct(pid);
483 if (IS_ERR(child)) {
484 ret = PTR_ERR(child);
485 goto out;
486 }
471 487
472 if (request == PTRACE_ATTACH) { 488 if (request == PTRACE_ATTACH) {
473 ret = ptrace_attach(child); 489 ret = ptrace_attach(child);