pid: reject allocations through dead ancestor pid namespaces

alloc_pid() checks PIDNS_ADDING only on the leaf pid namespace before
making a new struct pid visible in every ancestor namespace. That is
insufficient when an unborn descendant pid namespace outlives an
ancestor whose init task has already exited. The descendant can still be
initialized later through setns(), and the new pid is then published
into the dead ancestor as well.

Keep the existing ENOMEM behavior, but require PIDNS_ADDING to be set in
every namespace that will receive the new pid before publishing any of
them. This preserves the invariant that free_pid() never decrements
pid_allocated in a namespace whose child_reaper is no longer live.

Fixes: a3bdc23ba8 ("pid_namespace: allow opening pid_for_children before init was created")
Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
Reviewed-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
Jérémy Jean 2026-08-11 19:10:11 +00:00 committed by Christian Brauner
parent 86bcfe2e37
commit b64a9f67e0
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2

View File

@ -324,8 +324,10 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t *arg_set_tid,
* error path may try to wakeup the possibly freed ns->child_reaper.
*/
retval = -ENOMEM;
if (unlikely(!(ns->pid_allocated & PIDNS_ADDING)))
goto out_free;
for (upid = pid->numbers + ns->level; upid >= pid->numbers; --upid)
if (unlikely(!(upid->ns->pid_allocated & PIDNS_ADDING)))
goto out_free;
for (upid = pid->numbers + ns->level; upid >= pid->numbers; --upid) {
/* Make the PID visible to find_pid_ns. */
idr_replace(&upid->ns->idr, pid, upid->nr);