Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d36174bc authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Linus Torvalds
Browse files

uglify kill_pid_info() to fix kill() vs exec() race



kill_pid_info()->pid_task() could be the old leader of the execing process.
In that case it is possible that the leader will be released before we take
siglock. This means that kill_pid_info() (and thus sys_kill()) can return a
false -ESRCH.

Change the code to retry when lock_task_sighand() fails. The endless loop is
not possible, __exit_signal() both clears ->sighand and does detach_pid().

Signed-off-by: default avatarOleg Nesterov <oleg@tv-sign.ru>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Davide Libenzi <davidel@xmailserver.org>
Cc: Pavel Emelyanov <xemul@openvz.org>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent f374ada5
Loading
Loading
Loading
Loading
+12 −3
Original line number Original line Diff line number Diff line
@@ -1050,17 +1050,26 @@ int kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp)


int kill_pid_info(int sig, struct siginfo *info, struct pid *pid)
int kill_pid_info(int sig, struct siginfo *info, struct pid *pid)
{
{
	int error;
	int error = -ESRCH;
	struct task_struct *p;
	struct task_struct *p;


	rcu_read_lock();
	rcu_read_lock();
	if (unlikely(sig_needs_tasklist(sig)))
	if (unlikely(sig_needs_tasklist(sig)))
		read_lock(&tasklist_lock);
		read_lock(&tasklist_lock);


retry:
	p = pid_task(pid, PIDTYPE_PID);
	p = pid_task(pid, PIDTYPE_PID);
	error = -ESRCH;
	if (p) {
	if (p)
		error = group_send_sig_info(sig, info, p);
		error = group_send_sig_info(sig, info, p);
		if (unlikely(error == -ESRCH))
			/*
			 * The task was unhashed in between, try again.
			 * If it is dead, pid_task() will return NULL,
			 * if we race with de_thread() it will find the
			 * new leader.
			 */
			goto retry;
	}


	if (unlikely(sig_needs_tasklist(sig)))
	if (unlikely(sig_needs_tasklist(sig)))
		read_unlock(&tasklist_lock);
		read_unlock(&tasklist_lock);