proc: prevent reconfiguring subset=pid

Changing subset=pid on an existing procfs instance is not safe. If a
full procfs mount has entries hidden by overmounts, switching it to
subset=pid would hide the top-level procfs entries from lookup and
readdir while leaving the existing overmounts reachable.

Reject attempts to change the subset=pid state during reconfigure before
applying any other procfs mount options, so a failed reconfigure cannot
partially update the instance.

Signed-off-by: Alexey Gladkov <legion@kernel.org>
Link: https://patch.msgid.link/13295f40f642af5d6e7038d681d43132ad80f7b2.1777278334.git.legion@kernel.org
Reviewed-by: Aleksa Sarai <aleksa@amutable.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Alexey Gladkov 2026-04-27 10:26:06 +02:00 committed by Christian Brauner
parent a2a5eb6323
commit 1991a8f693

View File

@ -223,12 +223,17 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
return 0;
}
static void proc_apply_options(struct proc_fs_info *fs_info,
static int proc_apply_options(struct proc_fs_info *fs_info,
struct fs_context *fc,
struct user_namespace *user_ns)
{
struct proc_fs_context *ctx = fc->fs_private;
if ((ctx->mask & (1 << Opt_subset)) &&
fc->purpose == FS_CONTEXT_FOR_RECONFIGURE &&
ctx->pidonly != fs_info->pidonly)
return invalf(fc, "proc: subset=pid cannot be changed\n");
if (ctx->mask & (1 << Opt_gid))
fs_info->pid_gid = make_kgid(user_ns, ctx->gid);
if (ctx->mask & (1 << Opt_hidepid))
@ -240,6 +245,7 @@ static void proc_apply_options(struct proc_fs_info *fs_info,
put_pid_ns(fs_info->pid_ns);
fs_info->pid_ns = get_pid_ns(ctx->pid_ns);
}
return 0;
}
static int proc_fill_super(struct super_block *s, struct fs_context *fc)
@ -255,7 +261,9 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc)
fs_info->pid_ns = get_pid_ns(ctx->pid_ns);
fs_info->mounter_cred = get_cred(fc->cred);
proc_apply_options(fs_info, fc, current_user_ns());
ret = proc_apply_options(fs_info, fc, current_user_ns());
if (ret)
return ret;
/* User space would break if executables or devices appear on proc */
s->s_iflags |= SB_I_NOEXEC | SB_I_NODEV;
@ -304,8 +312,7 @@ static int proc_reconfigure(struct fs_context *fc)
sync_filesystem(sb);
proc_apply_options(fs_info, fc, current_user_ns());
return 0;
return proc_apply_options(fs_info, fc, current_user_ns());
}
static int proc_get_tree(struct fs_context *fc)