aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/ptrace.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 863eee8bff47..5b8dd98a230e 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -406,3 +406,85 @@ int ptrace_request(struct task_struct *child, long request,
406 406
407 return ret; 407 return ret;
408} 408}
409
410#ifndef __ARCH_SYS_PTRACE
411static int ptrace_get_task_struct(long request, long pid,
412 struct task_struct **childp)
413{
414 struct task_struct *child;
415 int ret;
416
417 /*
418 * Callers use child == NULL as an indication to exit early even
419 * when the return value is 0, so make sure it is non-NULL here.
420 */
421 *childp = NULL;
422
423 if (request == PTRACE_TRACEME) {
424 /*
425 * Are we already being traced?
426 */
427 if (current->ptrace & PT_PTRACED)
428 return -EPERM;
429 ret = security_ptrace(current->parent, current);
430 if (ret)
431 return -EPERM;
432 /*
433 * Set the ptrace bit in the process ptrace flags.
434 */
435 current->ptrace |= PT_PTRACED;
436 return 0;
437 }
438
439 /*
440 * You may not mess with init
441 */
442 if (pid == 1)
443 return -EPERM;
444
445 ret = -ESRCH;
446 read_lock(&tasklist_lock);
447 child = find_task_by_pid(pid);
448 if (child)
449 get_task_struct(child);
450 read_unlock(&tasklist_lock);
451 if (!child)
452 return -ESRCH;
453
454 *childp = child;
455 return 0;
456}
457
458asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
459{
460 struct task_struct *child;
461 long ret;
462
463 /*
464 * This lock_kernel fixes a subtle race with suid exec
465 */
466 lock_kernel();
467 ret = ptrace_get_task_struct(request, pid, &child);
468 if (!child)
469 goto out;
470
471 if (request == PTRACE_ATTACH) {
472 ret = ptrace_attach(child);
473 goto out;
474 }
475
476 ret = ptrace_check_attach(child, request == PTRACE_KILL);
477 if (ret < 0)
478 goto out_put_task_struct;
479
480 ret = arch_ptrace(child, request, addr, data);
481 if (ret < 0)
482 goto out_put_task_struct;
483
484 out_put_task_struct:
485 put_task_struct(child);
486 out:
487 unlock_kernel();
488 return ret;
489}
490#endif /* __ARCH_SYS_PTRACE */