On Thu, Jul 16, 2026 at 8:52 AM Li Chen <[email protected]> wrote:
>
> A kernel-created task can become visible before it has installed a new
> executable image or a valid userspace register frame. Exposing such a task
> through ptrace can disclose kernel setup state.
>
> Add a task-local embryonic flag and an internal clone argument for callers
> that need this lifecycle. Reject ptrace access until the creator clears the
> flag. Clear it with release ordering and observe it with acquire ordering.
> This orders visibility of the completed exec state with the transition.
>
> Existing fork, vfork, clone, and kernel-thread callers leave the argument
> unset and retain their current behavior.
>

> --- a/kernel/ptrace.c
> +++ b/kernel/ptrace.c
> @@ -56,6 +56,8 @@ bool ptracer_access_allowed(struct task_struct *tsk)
>         guard(rcu)();
>         if (ptrace_parent(tsk) != current)
>                 return false;
> +       if (task_is_embryonic_exec(tsk))
> +               return false;
>         es = task_exec_state_rcu(tsk);
>         return READ_ONCE(es->dumpable) == TASK_DUMPABLE_OWNER ||
>                ptracer_capable(tsk, es->user_ns);
> @@ -312,6 +314,8 @@ static int __ptrace_may_access(struct task_struct *task, 
> unsigned int mode)
>                 WARN(1, "denying ptrace access check without 
> PTRACE_MODE_*CREDS\n");
>                 return -EPERM;
>         }
> +       if (task_is_embryonic_exec(task))
> +               return -EPERM;

Would it be better to use a different error code?  -ECONNREFUSED?
After all, this isn't a permission failure per se.

There's a not-locally-obvious gotcha here: reading other process
attributes prior to calling task_is_embryonic_exec may result in
(security-relevant!) data races.  This should at least be documented
-- it's critical to check task_is_embryonic_exec *before* trying to
read credentials.  Also, I think /proc and many pidfd APIs have the
same issue.

--Andy

Reply via email to