]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
fs: move SB_I_USERNS_VISIBLE to FS_USERNS_MOUNT_RESTRICTED
authorChristian Brauner <brauner@kernel.org>
Mon, 27 Apr 2026 08:26:03 +0000 (10:26 +0200)
committerChristian Brauner <brauner@kernel.org>
Mon, 11 May 2026 21:13:01 +0000 (23:13 +0200)
Whether a filesystem's mounts need to undergo a visibility check in user
namespaces is a static property of the filesystem type, not a runtime
property of each superblock instance. Both proc and sysfs always set
SB_I_USERNS_VISIBLE on their superblocks unconditionally (sysfs does so
on first creation, and subsequent mounts reuse the same superblock).

Move this flag from sb->s_iflags (SB_I_USERNS_VISIBLE) to
file_system_type->fs_flags (FS_USERNS_MOUNT_RESTRICTED) so the intent
is expressed at the filesystem type level where it belongs.

All check sites are updated to test sb->s_type->fs_flags instead of
sb->s_iflags. The SB_I_NOEXEC and SB_I_NODEV flags remain on the
superblock as they are runtime properties set during fill_super.

Link: https://patch.msgid.link/72887c5b6204dc3adf5a53104f0be6bd8bc4f6cd.1777278334.git.legion@kernel.org
Reviewed-by: Aleksa Sarai <aleksa@amutable.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/namespace.c
fs/proc/root.c
fs/sysfs/mount.c
include/linux/fs.h
include/linux/fs/super_types.h
kernel/acct.c

index 047efa737ef92f7662cce4547f837343f75c39b4..e6e58117c778b0f743f1f0fe453a73b2ed472e1e 100644 (file)
@@ -1099,7 +1099,7 @@ static void mnt_add_to_ns(struct mnt_namespace *ns, struct mount *mnt)
        rb_link_node(&mnt->mnt_node, parent, link);
        rb_insert_color(&mnt->mnt_node, &ns->mounts);
 
-       if ((mnt->mnt.mnt_sb->s_iflags & SB_I_USERNS_VISIBLE) &&
+       if ((mnt->mnt.mnt_sb->s_type->fs_flags & FS_USERNS_MOUNT_RESTRICTED) &&
            mnt->mnt.mnt_root == mnt->mnt.mnt_sb->s_root)
                hlist_add_head(&mnt->mnt_ns_visible, &ns->mnt_visible_mounts);
 
@@ -6408,10 +6408,10 @@ static bool mount_too_revealing(const struct super_block *sb, int *new_mnt_flags
                return false;
 
        /* Can this filesystem be too revealing? */
-       s_iflags = sb->s_iflags;
-       if (!(s_iflags & SB_I_USERNS_VISIBLE))
+       if (!(sb->s_type->fs_flags & FS_USERNS_MOUNT_RESTRICTED))
                return false;
 
+       s_iflags = sb->s_iflags;
        if ((s_iflags & required_iflags) != required_iflags) {
                WARN_ONCE(1, "Expected s_iflags to contain 0x%lx\n",
                          required_iflags);
index 0f9100559471023c35d06cd4f466cf55d25e5512..b65053f9f0464af997ab87810b1921384a2d478d 100644 (file)
@@ -257,7 +257,7 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc)
        proc_apply_options(fs_info, fc, current_user_ns());
 
        /* User space would break if executables or devices appear on proc */
-       s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV;
+       s->s_iflags |= SB_I_NOEXEC | SB_I_NODEV;
        s->s_flags |= SB_NODIRATIME | SB_NOSUID | SB_NOEXEC;
        s->s_blocksize = 1024;
        s->s_blocksize_bits = 10;
@@ -359,7 +359,7 @@ static struct file_system_type proc_fs_type = {
        .init_fs_context        = proc_init_fs_context,
        .parameters             = proc_fs_parameters,
        .kill_sb                = proc_kill_sb,
-       .fs_flags               = FS_USERNS_MOUNT | FS_DISALLOW_NOTIFY_PERM,
+       .fs_flags               = FS_USERNS_MOUNT | FS_USERNS_MOUNT_RESTRICTED | FS_DISALLOW_NOTIFY_PERM,
 };
 
 void __init proc_root_init(void)
index b199e8ff79b1f93ef8708b0927ba33c2c6ff10fd..b45ea5d511e77f5e556da76ee7b6a42df7fc56ba 100644 (file)
@@ -32,8 +32,6 @@ static int sysfs_get_tree(struct fs_context *fc)
        if (ret)
                return ret;
 
-       if (kfc->new_sb_created)
-               fc->root->d_sb->s_iflags |= SB_I_USERNS_VISIBLE;
        return 0;
 }
 
@@ -93,7 +91,7 @@ static struct file_system_type sysfs_fs_type = {
        .name                   = "sysfs",
        .init_fs_context        = sysfs_init_fs_context,
        .kill_sb                = sysfs_kill_sb,
-       .fs_flags               = FS_USERNS_MOUNT,
+       .fs_flags               = FS_USERNS_MOUNT | FS_USERNS_MOUNT_RESTRICTED,
 };
 
 int __init sysfs_init(void)
index c37bb3c7de8bc84e94a400649320cb46e3a2a298..e7ff9f8b14855fc65b88c6080b2997e50de56a1e 100644 (file)
@@ -2281,6 +2281,7 @@ struct file_system_type {
 #define FS_MGTIME              64      /* FS uses multigrain timestamps */
 #define FS_LBS                 128     /* FS supports LBS */
 #define FS_POWER_FREEZE                256     /* Always freeze on suspend/hibernate */
+#define FS_USERNS_MOUNT_RESTRICTED 512 /* Restrict mount in userns if not already visible */
 #define FS_RENAME_DOES_D_MOVE  32768   /* FS will handle d_move() during rename() internally. */
        int (*init_fs_context)(struct fs_context *);
        const struct fs_parameter_spec *parameters;
index 383050e7fdf57c066efa235f083a2adc760afb80..182efbeb9520926d3a26a75f9d9f481d8f1d89e0 100644 (file)
@@ -326,7 +326,6 @@ struct super_block {
 #define SB_I_STABLE_WRITES 0x00000008  /* don't modify blks until WB is done */
 
 /* sb->s_iflags to limit user namespace mounts */
-#define SB_I_USERNS_VISIBLE            0x00000010 /* fstype already mounted */
 #define SB_I_IMA_UNVERIFIABLE_SIGNATURE        0x00000020
 #define SB_I_UNTRUSTED_MOUNTER         0x00000040
 #define SB_I_EVM_HMAC_UNSUPPORTED      0x00000080
index cbbf79d718cf46e8bf81402f1e8f78a2829f54b8..c440d43479ca587a3395768a8a686491bbd2a8f7 100644 (file)
@@ -249,7 +249,7 @@ static int acct_on(const char __user *name)
                return -EINVAL;
 
        /* Exclude procfs and sysfs. */
-       if (file_inode(file)->i_sb->s_iflags & SB_I_USERNS_VISIBLE)
+       if (file_inode(file)->i_sb->s_type->fs_flags & FS_USERNS_MOUNT_RESTRICTED)
                return -EINVAL;
 
        if (!(file->f_mode & FMODE_CAN_WRITE))