/** * ptrace_traceme -- helper for PTRACE_TRACEME * * Performs checks and sets PT_PTRACED. * Should be used by all ptrace implementations for PTRACE_TRACEME. */ static int ptrace_traceme(void) { int ret = -EPERM; write_lock_irq(&tasklist_lock); /* Are we already being traced? */ if (!current->ptrace) { ret = security_ptrace_traceme(current->parent); /* * Check PF_EXITING to ensure ->real_parent has not passed * exit_ptrace(). Otherwise we don't report the error but * pretend ->real_parent untraces us right after return. */ if (!ret && !(current->real_parent->flags & PF_EXITING)) { current->ptrace = PT_PTRACED; __ptrace_link(current, current->real_parent); } } write_unlock_irq(&tasklist_lock); return ret; }
/** * ptrace_traceme -- helper for PTRACE_TRACEME * * Performs checks and sets PT_PTRACED. * Should be used by all ptrace implementations for PTRACE_TRACEME. */ int ptrace_traceme(void) { int ret = -EPERM; /* * Are we already being traced? */ repeat: task_lock(current); if (!(current->ptrace & PT_PTRACED)) { /* * See ptrace_attach() comments about the locking here. */ unsigned long flags; if (!write_trylock_irqsave(&tasklist_lock, flags)) { task_unlock(current); do { cpu_relax(); } while (!write_can_lock(&tasklist_lock)); goto repeat; } ret = security_ptrace_traceme(current->parent); /* * Set the ptrace bit in the process ptrace flags. * Then link us on our parent's ptraced list. */ if (!ret) { current->ptrace |= PT_PTRACED; __ptrace_link(current, current->real_parent); } write_unlock_irqrestore(&tasklist_lock, flags); } task_unlock(current); return ret; }