summaryrefslogtreecommitdiff
path: root/fs/namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c279
1 files changed, 172 insertions, 107 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 854f4fc66469..ae5dc64f8b45 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -321,6 +321,7 @@ static struct mount *alloc_vfsmnt(const char *name)
INIT_HLIST_NODE(&mnt->mnt_slave);
INIT_HLIST_NODE(&mnt->mnt_mp_list);
INIT_HLIST_HEAD(&mnt->mnt_stuck_children);
+ INIT_HLIST_NODE(&mnt->mnt_ns_visible);
RB_CLEAR_NODE(&mnt->mnt_node);
mnt->mnt.mnt_idmap = &nop_mnt_idmap;
}
@@ -1079,7 +1080,7 @@ static void mnt_add_to_ns(struct mnt_namespace *ns, struct mount *mnt)
bool mnt_first_node = true, mnt_last_node = true;
WARN_ON(mnt_ns_attached(mnt));
- mnt->mnt_ns = ns;
+ WRITE_ONCE(mnt->mnt_ns, ns);
while (*link) {
parent = *link;
if (mnt->mnt_id_unique < node_to_mount(parent)->mnt_id_unique) {
@@ -1098,6 +1099,10 @@ 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_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);
+
mnt_notify_add(mnt);
}
@@ -1434,7 +1439,7 @@ EXPORT_SYMBOL(mntget);
void mnt_make_shortterm(struct vfsmount *mnt)
{
if (mnt)
- real_mount(mnt)->mnt_ns = NULL;
+ WRITE_ONCE(real_mount(mnt)->mnt_ns, NULL);
}
/**
@@ -1806,7 +1811,7 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
ns->nr_mounts--;
__touch_mnt_namespace(ns);
}
- p->mnt_ns = NULL;
+ WRITE_ONCE(p->mnt_ns, NULL);
if (how & UMOUNT_SYNC)
p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
@@ -2646,6 +2651,19 @@ static int attach_recursive_mnt(struct mount *source_mnt,
if (unlikely(shorter) && child != source_mnt)
mp = shorter;
+ /*
+ * If @q was locked it was meant to hide
+ * whatever was under it. Let @child take over
+ * that job and lock it, then we can unlock @q.
+ * That'll allow another namespace to shed @q
+ * and reveal @child. Clearly, that mounter
+ * consented to this by not severing the mount
+ * relationship. Otherwise, what's the point.
+ */
+ if (IS_MNT_LOCKED(q)) {
+ child->mnt.mnt_flags |= MNT_LOCKED;
+ q->mnt.mnt_flags &= ~MNT_LOCKED;
+ }
mnt_change_mountpoint(r, mp, q);
}
}
@@ -2722,7 +2740,7 @@ static inline struct mount *where_to_mount(const struct path *path,
* In all cases the location must not have been unmounted and the
* chosen mountpoint must be allowed to be mounted on. For "beneath"
* case we also require the location to be at the root of a mount
- * that has a parent (i.e. is not a root of some namespace).
+ * that has something mounted on top of it (i.e. has an overmount).
*/
static void do_lock_mount(const struct path *path,
struct pinned_mountpoint *res,
@@ -2890,6 +2908,9 @@ static int do_change_type(const struct path *path, int ms_flags)
for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL))
change_mnt_propagation(m, type);
+ guard(mount_locked_reader)();
+ touch_mnt_namespace(mnt->mnt_ns);
+
return 0;
}
@@ -2958,10 +2979,9 @@ static inline bool may_copy_tree(const struct path *path)
}
static struct mount *__do_loopback(const struct path *old_path,
- unsigned int flags, unsigned int copy_flags)
+ bool recurse, unsigned int copy_flags)
{
struct mount *old = real_mount(old_path->mnt);
- bool recurse = flags & AT_RECURSIVE;
if (IS_MNT_UNBINDABLE(old))
return ERR_PTR(-EINVAL);
@@ -2972,18 +2992,6 @@ static struct mount *__do_loopback(const struct path *old_path,
if (!recurse && __has_locked_children(old, old_path->dentry))
return ERR_PTR(-EINVAL);
- /*
- * When creating a new mount namespace we don't want to copy over
- * mounts of mount namespaces to avoid the risk of cycles and also to
- * minimize the default complex interdependencies between mount
- * namespaces.
- *
- * We could ofc just check whether all mount namespace files aren't
- * creating cycles but really let's keep this simple.
- */
- if (!(flags & OPEN_TREE_NAMESPACE))
- copy_flags |= CL_COPY_MNT_NS_FILE;
-
if (recurse)
return copy_tree(old, old_path->dentry, copy_flags);
@@ -2998,7 +3006,6 @@ static int do_loopback(const struct path *path, const char *old_name,
{
struct path old_path __free(path_put) = {};
struct mount *mnt = NULL;
- unsigned int flags = recurse ? AT_RECURSIVE : 0;
int err;
if (!old_name || !*old_name)
@@ -3017,7 +3024,7 @@ static int do_loopback(const struct path *path, const char *old_name,
if (!check_mnt(mp.parent))
return -EINVAL;
- mnt = __do_loopback(&old_path, flags, 0);
+ mnt = __do_loopback(&old_path, recurse, CL_COPY_MNT_NS_FILE);
if (IS_ERR(mnt))
return PTR_ERR(mnt);
@@ -3055,7 +3062,7 @@ static struct mnt_namespace *get_detached_copy(const struct path *path, unsigned
ns->seq_origin = src_mnt_ns->ns.ns_id;
}
- mnt = __do_loopback(path, flags, 0);
+ mnt = __do_loopback(path, (flags & AT_RECURSIVE), CL_COPY_MNT_NS_FILE);
if (IS_ERR(mnt)) {
emptied_ns = ns;
return ERR_CAST(mnt);
@@ -3087,7 +3094,13 @@ static struct file *open_detached_copy(struct path *path, unsigned int flags)
return file;
}
-static struct mnt_namespace *create_new_namespace(struct path *path, unsigned int flags)
+enum mount_copy_flags_t {
+ MOUNT_COPY_RECURSIVE = (1 << 0),
+ MOUNT_COPY_NEW = (1 << 1),
+};
+
+static struct mnt_namespace *create_new_namespace(struct path *path,
+ enum mount_copy_flags_t flags)
{
struct mnt_namespace *ns = current->nsproxy->mnt_ns;
struct user_namespace *user_ns = current_user_ns();
@@ -3096,7 +3109,10 @@ static struct mnt_namespace *create_new_namespace(struct path *path, unsigned in
struct path to_path;
struct mount *mnt;
unsigned int copy_flags = 0;
- bool locked = false;
+ bool locked = false, recurse = flags & MOUNT_COPY_RECURSIVE;
+
+ if (unlikely(!d_can_lookup(path->dentry)))
+ return ERR_PTR(-ENOTDIR);
if (user_ns != ns->user_ns)
copy_flags |= CL_SLAVE;
@@ -3131,11 +3147,14 @@ static struct mnt_namespace *create_new_namespace(struct path *path, unsigned in
}
/*
- * We don't emulate unshare()ing a mount namespace. We stick
- * to the restrictions of creating detached bind-mounts. It
- * has a lot saner and simpler semantics.
+ * We don't emulate unshare()ing a mount namespace. We stick to
+ * the restrictions of creating detached bind-mounts. It has a
+ * lot saner and simpler semantics.
*/
- mnt = __do_loopback(path, flags, copy_flags);
+ if (flags & MOUNT_COPY_NEW)
+ mnt = clone_mnt(real_mount(path->mnt), path->dentry, copy_flags);
+ else
+ mnt = __do_loopback(path, recurse, copy_flags);
scoped_guard(mount_writer) {
if (IS_ERR(mnt)) {
emptied_ns = new_ns;
@@ -3164,7 +3183,8 @@ static struct mnt_namespace *create_new_namespace(struct path *path, unsigned in
return new_ns;
}
-static struct file *open_new_namespace(struct path *path, unsigned int flags)
+static struct file *open_new_namespace(struct path *path,
+ enum mount_copy_flags_t flags)
{
struct mnt_namespace *new_ns;
@@ -3217,7 +3237,7 @@ static struct file *vfs_open_tree(int dfd, const char __user *filename, unsigned
return ERR_PTR(ret);
if (flags & OPEN_TREE_NAMESPACE)
- return open_new_namespace(&path, flags);
+ return open_new_namespace(&path, (flags & AT_RECURSIVE) ? MOUNT_COPY_RECURSIVE : 0);
if (flags & OPEN_TREE_CLONE)
return open_detached_copy(&path, flags);
@@ -3294,9 +3314,9 @@ static void mnt_warn_timestamp_expiry(const struct path *mountpoint,
(ktime_get_real_seconds() + TIME_UPTIME_SEC_MAX > sb->s_time_max)) {
char *buf, *mntpath;
- buf = (char *)__get_free_page(GFP_KERNEL);
+ buf = __getname();
if (buf)
- mntpath = d_path(mountpoint, buf, PAGE_SIZE);
+ mntpath = d_path(mountpoint, buf, PATH_MAX);
else
mntpath = ERR_PTR(-ENOMEM);
if (IS_ERR(mntpath))
@@ -3309,8 +3329,7 @@ static void mnt_warn_timestamp_expiry(const struct path *mountpoint,
(unsigned long long)sb->s_time_max);
sb->s_iflags |= SB_I_TS_EXPIRY_WARNED;
- if (buf)
- free_page((unsigned long)buf);
+ __putname(buf);
}
}
@@ -3465,6 +3484,10 @@ static int do_set_group(const struct path *from_path, const struct path *to_path
list_add(&to->mnt_share, &from->mnt_share);
set_mnt_shared(to);
}
+
+ guard(mount_locked_reader)();
+ touch_mnt_namespace(to->mnt_ns);
+
return 0;
}
@@ -3513,8 +3536,6 @@ static bool mount_is_ancestor(const struct mount *p1, const struct mount *p2)
* @mnt_to: mount under which to mount
* @mp: mountpoint of @mnt_to
*
- * - Make sure that nothing can be mounted beneath the caller's current
- * root or the rootfs of the namespace.
* - Make sure that the caller can unmount the topmost mount ensuring
* that the caller could reveal the underlying mountpoint.
* - Ensure that nothing has been mounted on top of @mnt_from before we
@@ -3528,26 +3549,14 @@ static bool mount_is_ancestor(const struct mount *p1, const struct mount *p2)
*/
static int can_move_mount_beneath(const struct mount *mnt_from,
const struct mount *mnt_to,
- const struct mountpoint *mp)
+ struct pinned_mountpoint *mp)
{
struct mount *parent_mnt_to = mnt_to->mnt_parent;
- if (IS_MNT_LOCKED(mnt_to))
- return -EINVAL;
-
/* Avoid creating shadow mounts during mount propagation. */
if (mnt_from->overmount)
return -EINVAL;
- /*
- * Mounting beneath the rootfs only makes sense when the
- * semantics of pivot_root(".", ".") are used.
- */
- if (&mnt_to->mnt == current->fs->root.mnt)
- return -EINVAL;
- if (parent_mnt_to == current->nsproxy->mnt_ns->root)
- return -EINVAL;
-
if (mount_is_ancestor(mnt_to, mnt_from))
return -EINVAL;
@@ -3557,7 +3566,7 @@ static int can_move_mount_beneath(const struct mount *mnt_from,
* propagating a copy @c of @mnt_from on top of @mnt_to. This
* defeats the whole purpose of mounting beneath another mount.
*/
- if (propagation_would_overmount(parent_mnt_to, mnt_to, mp))
+ if (propagation_would_overmount(parent_mnt_to, mnt_to, mp->mp))
return -EINVAL;
/*
@@ -3573,7 +3582,7 @@ static int can_move_mount_beneath(const struct mount *mnt_from,
* @mnt_from beneath @mnt_to.
*/
if (check_mnt(mnt_from) &&
- propagation_would_overmount(parent_mnt_to, mnt_from, mp))
+ propagation_would_overmount(parent_mnt_to, mnt_from, mp->mp))
return -EINVAL;
return 0;
@@ -3682,7 +3691,7 @@ static int do_move_mount(const struct path *old_path,
if (mp.parent != over->mnt_parent)
over = mp.parent->overmount;
- err = can_move_mount_beneath(old, over, mp.mp);
+ err = can_move_mount_beneath(old, over, &mp);
if (err)
return err;
}
@@ -4231,8 +4240,8 @@ struct mnt_namespace *copy_mnt_ns(u64 flags, struct mnt_namespace *ns,
struct user_namespace *user_ns, struct fs_struct *new_fs)
{
struct mnt_namespace *new_ns;
- struct vfsmount *rootmnt __free(mntput) = NULL;
- struct vfsmount *pwdmnt __free(mntput) = NULL;
+ struct path old_root __free(path_put) = {};
+ struct path old_pwd __free(path_put) = {};
struct mount *p, *q;
struct mount *old;
struct mount *new;
@@ -4252,11 +4261,18 @@ struct mnt_namespace *copy_mnt_ns(u64 flags, struct mnt_namespace *ns,
return new_ns;
guard(namespace_excl)();
- /* First pass: copy the tree topology */
- copy_flags = CL_COPY_UNBINDABLE | CL_EXPIRE;
+
+ if (flags & CLONE_EMPTY_MNTNS)
+ copy_flags = 0;
+ else
+ copy_flags = CL_COPY_UNBINDABLE | CL_EXPIRE;
if (user_ns != ns->user_ns)
copy_flags |= CL_SLAVE;
- new = copy_tree(old, old->mnt.mnt_root, copy_flags);
+
+ if (flags & CLONE_EMPTY_MNTNS)
+ new = clone_mnt(old, old->mnt.mnt_root, copy_flags);
+ else
+ new = copy_tree(old, old->mnt.mnt_root, copy_flags);
if (IS_ERR(new)) {
emptied_ns = new_ns;
return ERR_CAST(new);
@@ -4267,33 +4283,53 @@ struct mnt_namespace *copy_mnt_ns(u64 flags, struct mnt_namespace *ns,
}
new_ns->root = new;
- /*
- * Second pass: switch the tsk->fs->* elements and mark new vfsmounts
- * as belonging to new namespace. We have already acquired a private
- * fs_struct, so tsk->fs->lock is not needed.
- */
- p = old;
- q = new;
- while (p) {
- mnt_add_to_ns(new_ns, q);
- new_ns->nr_mounts++;
+ if (flags & CLONE_EMPTY_MNTNS) {
+ /*
+ * Empty mount namespace: only the root mount exists.
+ * Reset root and pwd to the cloned mount's root dentry.
+ */
if (new_fs) {
- if (&p->mnt == new_fs->root.mnt) {
- new_fs->root.mnt = mntget(&q->mnt);
- rootmnt = &p->mnt;
- }
- if (&p->mnt == new_fs->pwd.mnt) {
- new_fs->pwd.mnt = mntget(&q->mnt);
- pwdmnt = &p->mnt;
+ old_root = new_fs->root;
+ old_pwd = new_fs->pwd;
+
+ new_fs->root.mnt = mntget(&new->mnt);
+ new_fs->root.dentry = dget(new->mnt.mnt_root);
+
+ new_fs->pwd.mnt = mntget(&new->mnt);
+ new_fs->pwd.dentry = dget(new->mnt.mnt_root);
+ }
+ mnt_add_to_ns(new_ns, new);
+ new_ns->nr_mounts++;
+ } else {
+ /*
+ * Full copy: walk old and new trees in parallel, switching
+ * the tsk->fs->* elements and marking new vfsmounts as
+ * belonging to new namespace. We have already acquired a
+ * private fs_struct, so tsk->fs->lock is not needed.
+ */
+ p = old;
+ q = new;
+ while (p) {
+ mnt_add_to_ns(new_ns, q);
+ new_ns->nr_mounts++;
+ if (new_fs) {
+ if (&p->mnt == new_fs->root.mnt) {
+ old_root.mnt = new_fs->root.mnt;
+ new_fs->root.mnt = mntget(&q->mnt);
+ }
+ if (&p->mnt == new_fs->pwd.mnt) {
+ old_pwd.mnt = new_fs->pwd.mnt;
+ new_fs->pwd.mnt = mntget(&q->mnt);
+ }
}
+ p = next_mnt(p, old);
+ q = next_mnt(q, new);
+ if (!q)
+ break;
+ // an mntns binding we'd skipped?
+ while (p->mnt.mnt_root != q->mnt.mnt_root)
+ p = next_mnt(skip_mnt_tree(p), old);
}
- p = next_mnt(p, old);
- q = next_mnt(q, new);
- if (!q)
- break;
- // an mntns binding we'd skipped?
- while (p->mnt.mnt_root != q->mnt.mnt_root)
- p = next_mnt(skip_mnt_tree(p), old);
}
ns_tree_add_raw(new_ns);
return new_ns;
@@ -4414,11 +4450,15 @@ SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags,
unsigned int mnt_flags = 0;
long ret;
- if (!may_mount())
+ if ((flags & ~(FSMOUNT_CLOEXEC | FSMOUNT_NAMESPACE)) != 0)
+ return -EINVAL;
+
+ if ((flags & FSMOUNT_NAMESPACE) &&
+ !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
return -EPERM;
- if ((flags & ~(FSMOUNT_CLOEXEC)) != 0)
- return -EINVAL;
+ if (!(flags & FSMOUNT_NAMESPACE) && !may_mount())
+ return -EPERM;
if (attr_flags & ~FSMOUNT_VALID_FLAGS)
return -EINVAL;
@@ -4473,6 +4513,10 @@ SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags,
new_mnt = vfs_create_mount(fc);
if (IS_ERR(new_mnt))
return PTR_ERR(new_mnt);
+ if (new_mnt->mnt_sb->s_flags & SB_NOUSER) {
+ mntput(new_mnt);
+ return -EINVAL;
+ }
new_mnt->mnt_flags = mnt_flags;
new_path.dentry = dget(fc->root);
@@ -4485,6 +4529,10 @@ SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags,
*/
vfs_clean_context(fc);
+ if (flags & FSMOUNT_NAMESPACE)
+ return FD_ADD((flags & FSMOUNT_CLOEXEC) ? O_CLOEXEC : 0,
+ open_new_namespace(&new_path, MOUNT_COPY_NEW));
+
ns = alloc_mnt_ns(current->nsproxy->mnt_ns->user_ns, true);
if (IS_ERR(ns))
return PTR_ERR(ns);
@@ -5649,14 +5697,14 @@ static int grab_requested_root(struct mnt_namespace *ns, struct path *root)
if (mnt_ns_empty(ns))
return -ENOENT;
- first = child = ns->root;
- for (;;) {
- child = listmnt_next(child, false);
- if (!child)
- return -ENOENT;
- if (child->mnt_parent == first)
+ first = ns->root;
+ for (child = node_to_mount(ns->mnt_first_node); child;
+ child = listmnt_next(child, false)) {
+ if (child != first && child->mnt_parent == first)
break;
}
+ if (!child)
+ return -ENOENT;
root->mnt = mntget(&child->mnt);
root->dentry = dget(root->mnt->mnt_root);
@@ -5951,7 +5999,7 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req,
return -EPERM;
}
- ks = kmalloc(sizeof(*ks), GFP_KERNEL_ACCOUNT);
+ ks = kmalloc_obj(*ks, GFP_KERNEL_ACCOUNT);
if (!ks)
return -ENOMEM;
@@ -6143,12 +6191,14 @@ static void __init init_mount_tree(void)
struct path root;
/*
- * We create two mounts:
+ * We create three mounts:
*
* (1) nullfs with mount id 1
* (2) mutable rootfs with mount id 2
+ * (3) private nullfs for kthreads (SB_KERNMOUNT)
*
- * with (2) mounted on top of (1).
+ * with (2) mounted on top of (1). The init_task's root and pwd
+ * are pointed at (3) so all kthreads start isolated in nullfs.
*/
nullfs_mnt = vfs_kern_mount(&nullfs_fs_type, 0, "nullfs", NULL);
if (IS_ERR(nullfs_mnt))
@@ -6188,12 +6238,14 @@ static void __init init_mount_tree(void)
init_mnt_ns.nr_mounts++;
}
+ nullfs_mnt = kern_mount(&nullfs_fs_type);
+ if (IS_ERR(nullfs_mnt))
+ panic("VFS: Failed to create private nullfs instance");
+ root.mnt = nullfs_mnt;
+ root.dentry = nullfs_mnt->mnt_root;
+
init_task.nsproxy->mnt_ns = &init_mnt_ns;
get_mnt_ns(&init_mnt_ns);
-
- /* The root and pwd always point to the mutable rootfs. */
- root.mnt = mnt;
- root.dentry = mnt->mnt_root;
set_fs_pwd(current->fs, &root);
set_fs_root(current->fs, &root);
@@ -6218,8 +6270,7 @@ void __init mnt_init(void)
HASH_ZERO,
&mp_hash_shift, &mp_hash_mask, 0, 0);
- if (!mount_hashtable || !mountpoint_hashtable)
- panic("Failed to allocate mount hash table\n");
+ super_dev_init();
kernfs_init();
@@ -6233,6 +6284,7 @@ void __init mnt_init(void)
shmem_init();
init_rootfs();
init_mount_tree();
+ failfs_init();
}
void put_mnt_ns(struct mnt_namespace *ns)
@@ -6242,7 +6294,7 @@ void put_mnt_ns(struct mnt_namespace *ns)
guard(namespace_excl)();
emptied_ns = ns;
guard(mount_writer)();
- umount_tree(ns->root, 0);
+ umount_tree(ns->root, UMOUNT_CONNECTED);
}
struct vfsmount *kern_mount(struct file_system_type *type)
@@ -6310,20 +6362,26 @@ static bool mnt_already_visible(struct mnt_namespace *ns,
int *new_mnt_flags)
{
int new_flags = *new_mnt_flags;
- struct mount *mnt, *n;
+ struct mount *mnt;
+
+ /* Don't acquire namespace semaphore without a good reason. */
+ if (hlist_empty(&ns->mnt_visible_mounts))
+ return false;
guard(namespace_shared)();
- rbtree_postorder_for_each_entry_safe(mnt, n, &ns->mounts, mnt_node) {
+ hlist_for_each_entry(mnt, &ns->mnt_visible_mounts, mnt_ns_visible) {
+ const struct super_block *sb_visible = mnt->mnt.mnt_sb;
struct mount *child;
int mnt_flags;
- if (mnt->mnt.mnt_sb->s_type != sb->s_type)
+ if (sb_visible->s_type != sb->s_type)
continue;
- /* This mount is not fully visible if it's root directory
- * is not the root directory of the filesystem.
+ /*
+ * Restricted variants are not compatible with anything, even
+ * other restricted variants.
*/
- if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root)
+ if (sb_visible->s_iflags & SB_I_RESTRICTED_VARIANT)
continue;
/* A local view of the mount flags */
@@ -6375,16 +6433,23 @@ 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);
return true;
}
+ /*
+ * Restricted variants don't need an already visible mount because they
+ * don't expose the full filesystem view.
+ */
+ if (s_iflags & SB_I_RESTRICTED_VARIANT)
+ return false;
+
return !mnt_already_visible(ns, sb, new_mnt_flags);
}