Re: [PATCH v2 2/5] sched,ptrace: Fix ptrace_check_attach() vs PREEMPT_RT

From: Oleg Nesterov
Date: Mon Apr 25 2022 - 10:35:56 EST


On 04/21, Peter Zijlstra wrote:
>
> +static void clear_traced_quiesce(void)
> +{
> + spin_lock_irq(&current->sighand->siglock);
> + WARN_ON_ONCE(!(current->jobctl & JOBCTL_TRACED_QUIESCE));

This WARN_ON_ONCE() doesn't look right, the task can be killed right
after ptrace_stop() sets JOBCTL_TRACED | JOBCTL_TRACED_QUIESCE and
drops siglock.

> @@ -2290,14 +2303,26 @@ static int ptrace_stop(int exit_code, in
> /*
> * Don't want to allow preemption here, because
> * sys_ptrace() needs this task to be inactive.
> - *
> - * XXX: implement read_unlock_no_resched().
> */
> preempt_disable();
> read_unlock(&tasklist_lock);
> - cgroup_enter_frozen();
> + cgroup_enter_frozen(); // XXX broken on PREEMPT_RT !!!
> +
> + /*
> + * JOBCTL_TRACE_QUIESCE bridges the gap between
> + * set_current_state(TASK_TRACED) above and schedule() below.
> + * There must not be any blocking (specifically anything that
> + * touched ->saved_state on PREEMPT_RT) between here and
> + * schedule().
> + *
> + * ptrace_check_attach() relies on this with its
> + * wait_task_inactive() usage.
> + */
> + clear_traced_quiesce();

Well, I think it should be called earlier under tasklist_lock,
before preempt_disable() above.

We need tasklist_lock to protect ->parent, debugger can be killed
and go away right after read_unlock(&tasklist_lock).

Still trying to convince myself everything is right with
JOBCTL_STOPPED/TRACED ...

Oleg.