All of lore.kernel.org
 help / color / mirror / Atom feed
From: Oleg Nesterov <oleg@redhat.com>
To: bsegall@google.com
Cc: linux-kernel@vger.kernel.org,
	Roland McGrath <roland@hack.frob.com>,
	Andrew Morton <akpm@linux-foundation.org>,
	Tejun Heo <tj@kernel.org>
Subject: Re: [PATCH] ptrace: fix PTRACE_LISTEN race corrupting task->state
Date: Fri, 24 Feb 2017 17:36:11 +0100	[thread overview]
Message-ID: <20170224163611.GA24902@redhat.com> (raw)
In-Reply-To: <xm2637f7js85.fsf@bsegall-linux.mtv.corp.google.com>

(add akpm, we usually route ptrace fixes via -mm tree)

On 02/21, bsegall@google.com wrote:
>
> --- a/kernel/ptrace.c
> +++ b/kernel/ptrace.c
> @@ -184,10 +184,14 @@ static void ptrace_unfreeze_traced(struct task_struct *task)
>  
>         WARN_ON(!task->ptrace || task->parent != current);
>  
> +       /*
> +        * Double check __TASK_TRACED under the lock to prevent corrupting state
> +        * in case of a ptrace_trap_notify wakeup
> +        */
>         spin_lock_irq(&task->sighand->siglock);
>         if (__fatal_signal_pending(task))
>                 wake_up_state(task, __TASK_TRACED);
> -       else
> +       else if (task->state == __TASK_TRACED)
>                 task->state = TASK_TRACED;
>         spin_unlock_irq(&task->sighand->siglock);

So yes, I think your patch is fine except the comment should explain that
we need this because PTRACE_LISTEN makes ptrace_trap_notify() possible. And
perhaps it would be better to do the 2nd check before fatal_signal_pending:

	if (task->state == __TASK_TRACED) {
		if (__fatal_signal_pending(task))
			wake_up_state(task, __TASK_TRACED);
		else
			task->state = TASK_TRACED;
	}

just to make the logic more clear. wake_up_state(__TASK_TRACED) can
never hurt if the task is killed, just it doesn't look strictly correct
if the tracee was already woken. But this is minor.



You know, I'd prefer another fix, see below.

Why. ptrace_unfreeze_traced() assumes that - since ptrace_freeze_traced()
checks PTRACE_LISTEN - nobody but us can wake the tracee up. So the
__TASK_TRACED check at the start of ptrace_unfreeze_traced() means that
the tracee is still freezed, it was not woken up by (say) PTRACE_CONT.

IOW, currently we assume that only the caller of ptrace_freeze_traced()
can do the __TASK_TRACED -> WHATEVER transition.

However, as you pointed out, I forgot that JOBCTL_LISTENING set by LISTEN
breaks this assumption, and imo it would be nice to fix this.

What do you think? I won't insist too much if you prefer your simple change.

Oleg.

--- x/kernel/ptrace.c
+++ x/kernel/ptrace.c
@@ -174,6 +174,18 @@
 	return ret;
 }
 
+static bool __ptrace_unfreeze_traced(struct task_struct *task)
+{
+	bool killed = __fatal_signal_pending(task);
+
+	if (killed)
+		wake_up_state(task, __TASK_TRACED);
+	else
+		task->state = TASK_TRACED;
+
+	return !killed'
+}
+
 static void ptrace_unfreeze_traced(struct task_struct *task)
 {
 	if (task->state != __TASK_TRACED)
@@ -182,10 +194,7 @@
 	WARN_ON(!task->ptrace || task->parent != current);
 
 	spin_lock_irq(&task->sighand->siglock);
-	if (__fatal_signal_pending(task))
-		wake_up_state(task, __TASK_TRACED);
-	else
-		task->state = TASK_TRACED;
+	__ptrace_unfreeze_traced(task);
 	spin_unlock_irq(&task->sighand->siglock);
 }
 
@@ -993,7 +1002,12 @@
 			break;
 
 		si = child->last_siginfo;
-		if (likely(si && (si->si_code >> 8) == PTRACE_EVENT_STOP)) {
+		/*
+		 * Once we set JOBCTL_LISTENING we do not own child->state,
+		 * need to unfreeze first.
+		 */
+		if (__ptrace_unfreeze_traced(child) &&
+		    likely(si && (si->si_code >> 8) == PTRACE_EVENT_STOP)) {
 			child->jobctl |= JOBCTL_LISTENING;
 			/*
 			 * If NOTIFY is set, it means event happened between

  parent reply	other threads:[~2017-02-24 16:39 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-02-21 18:47 [PATCH] ptrace: fix PTRACE_LISTEN race corrupting task->state bsegall
2017-02-22 16:55 ` Oleg Nesterov
2017-02-22 17:03   ` Oleg Nesterov
2017-02-22 17:56   ` bsegall
2017-02-24 16:36 ` Oleg Nesterov [this message]
2017-02-27 18:08   ` bsegall
2017-04-04 21:47   ` [PATCHv2] " bsegall
2017-04-04 21:53     ` Andrew Morton
2017-04-05 12:36       ` Oleg Nesterov
2017-04-05 12:30     ` Oleg Nesterov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170224163611.GA24902@redhat.com \
    --to=oleg@redhat.com \
    --cc=akpm@linux-foundation.org \
    --cc=bsegall@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=roland@hack.frob.com \
    --cc=tj@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.