/**
 * 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;
}
Exemple #2
0
/**
 * 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;
}