Merge tag 'auxdisplay-for-linus-v5.15-rc1' of git://github.com/ojeda/linux
[linux-2.6-microblaze.git] / fs / namespace.c
index c3f1a78..659a8f3 100644 (file)
@@ -203,7 +203,8 @@ static struct mount *alloc_vfsmnt(const char *name)
                        goto out_free_cache;
 
                if (name) {
-                       mnt->mnt_devname = kstrdup_const(name, GFP_KERNEL);
+                       mnt->mnt_devname = kstrdup_const(name,
+                                                        GFP_KERNEL_ACCOUNT);
                        if (!mnt->mnt_devname)
                                goto out_free_id;
                }
@@ -1715,18 +1716,14 @@ static inline bool may_mount(void)
        return ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN);
 }
 
-#ifdef CONFIG_MANDATORY_FILE_LOCKING
-static inline bool may_mandlock(void)
+static void warn_mandlock(void)
 {
-       return capable(CAP_SYS_ADMIN);
+       pr_warn_once("=======================================================\n"
+                    "WARNING: The mand mount option has been deprecated and\n"
+                    "         and is ignored by this kernel. Remove the mand\n"
+                    "         option from the mount to silence this warning.\n"
+                    "=======================================================\n");
 }
-#else
-static inline bool may_mandlock(void)
-{
-       pr_warn("VFS: \"mand\" mount option not supported");
-       return false;
-}
-#endif
 
 static int can_umount(const struct path *path, int flags)
 {
@@ -1938,6 +1935,20 @@ void drop_collected_mounts(struct vfsmount *mnt)
        namespace_unlock();
 }
 
+static bool has_locked_children(struct mount *mnt, struct dentry *dentry)
+{
+       struct mount *child;
+
+       list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
+               if (!is_subdir(child->mnt_mountpoint, dentry))
+                       continue;
+
+               if (child->mnt.mnt_flags & MNT_LOCKED)
+                       return true;
+       }
+       return false;
+}
+
 /**
  * clone_private_mount - create a private clone of a path
  * @path: path to clone
@@ -1953,10 +1964,19 @@ struct vfsmount *clone_private_mount(const struct path *path)
        struct mount *old_mnt = real_mount(path->mnt);
        struct mount *new_mnt;
 
+       down_read(&namespace_sem);
        if (IS_MNT_UNBINDABLE(old_mnt))
-               return ERR_PTR(-EINVAL);
+               goto invalid;
+
+       if (!check_mnt(old_mnt))
+               goto invalid;
+
+       if (has_locked_children(old_mnt, path->dentry))
+               goto invalid;
 
        new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE);
+       up_read(&namespace_sem);
+
        if (IS_ERR(new_mnt))
                return ERR_CAST(new_mnt);
 
@@ -1964,6 +1984,10 @@ struct vfsmount *clone_private_mount(const struct path *path)
        new_mnt->mnt_ns = MNT_NS_INTERNAL;
 
        return &new_mnt->mnt;
+
+invalid:
+       up_read(&namespace_sem);
+       return ERR_PTR(-EINVAL);
 }
 EXPORT_SYMBOL_GPL(clone_private_mount);
 
@@ -2315,19 +2339,6 @@ static int do_change_type(struct path *path, int ms_flags)
        return err;
 }
 
-static bool has_locked_children(struct mount *mnt, struct dentry *dentry)
-{
-       struct mount *child;
-       list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
-               if (!is_subdir(child->mnt_mountpoint, dentry))
-                       continue;
-
-               if (child->mnt.mnt_flags & MNT_LOCKED)
-                       return true;
-       }
-       return false;
-}
-
 static struct mount *__do_loopback(struct path *old_path, int recurse)
 {
        struct mount *mnt = ERR_PTR(-EINVAL), *old = real_mount(old_path->mnt);
@@ -2684,6 +2695,78 @@ out:
        return ret;
 }
 
+static int do_set_group(struct path *from_path, struct path *to_path)
+{
+       struct mount *from, *to;
+       int err;
+
+       from = real_mount(from_path->mnt);
+       to = real_mount(to_path->mnt);
+
+       namespace_lock();
+
+       err = -EINVAL;
+       /* To and From must be mounted */
+       if (!is_mounted(&from->mnt))
+               goto out;
+       if (!is_mounted(&to->mnt))
+               goto out;
+
+       err = -EPERM;
+       /* We should be allowed to modify mount namespaces of both mounts */
+       if (!ns_capable(from->mnt_ns->user_ns, CAP_SYS_ADMIN))
+               goto out;
+       if (!ns_capable(to->mnt_ns->user_ns, CAP_SYS_ADMIN))
+               goto out;
+
+       err = -EINVAL;
+       /* To and From paths should be mount roots */
+       if (from_path->dentry != from_path->mnt->mnt_root)
+               goto out;
+       if (to_path->dentry != to_path->mnt->mnt_root)
+               goto out;
+
+       /* Setting sharing groups is only allowed across same superblock */
+       if (from->mnt.mnt_sb != to->mnt.mnt_sb)
+               goto out;
+
+       /* From mount root should be wider than To mount root */
+       if (!is_subdir(to->mnt.mnt_root, from->mnt.mnt_root))
+               goto out;
+
+       /* From mount should not have locked children in place of To's root */
+       if (has_locked_children(from, to->mnt.mnt_root))
+               goto out;
+
+       /* Setting sharing groups is only allowed on private mounts */
+       if (IS_MNT_SHARED(to) || IS_MNT_SLAVE(to))
+               goto out;
+
+       /* From should not be private */
+       if (!IS_MNT_SHARED(from) && !IS_MNT_SLAVE(from))
+               goto out;
+
+       if (IS_MNT_SLAVE(from)) {
+               struct mount *m = from->mnt_master;
+
+               list_add(&to->mnt_slave, &m->mnt_slave_list);
+               to->mnt_master = m;
+       }
+
+       if (IS_MNT_SHARED(from)) {
+               to->mnt_group_id = from->mnt_group_id;
+               list_add(&to->mnt_share, &from->mnt_share);
+               lock_mount_hash();
+               set_mnt_shared(to);
+               unlock_mount_hash();
+       }
+
+       err = 0;
+out:
+       namespace_unlock();
+       return err;
+}
+
 static int do_move_mount(struct path *old_path, struct path *new_path)
 {
        struct mnt_namespace *ns;
@@ -3179,8 +3262,8 @@ int path_mount(const char *dev_name, struct path *path,
                return ret;
        if (!may_mount())
                return -EPERM;
-       if ((flags & SB_MANDLOCK) && !may_mandlock())
-               return -EPERM;
+       if (flags & SB_MANDLOCK)
+               warn_mandlock();
 
        /* Default to relatime unless overriden */
        if (!(flags & MS_NOATIME))
@@ -3288,7 +3371,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns, bool a
        if (!ucounts)
                return ERR_PTR(-ENOSPC);
 
-       new_ns = kzalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
+       new_ns = kzalloc(sizeof(struct mnt_namespace), GFP_KERNEL_ACCOUNT);
        if (!new_ns) {
                dec_mnt_namespaces(ucounts);
                return ERR_PTR(-ENOMEM);
@@ -3464,9 +3547,10 @@ out_type:
        return ret;
 }
 
-#define FSMOUNT_VALID_FLAGS \
-       (MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID | MOUNT_ATTR_NODEV | \
-        MOUNT_ATTR_NOEXEC | MOUNT_ATTR__ATIME | MOUNT_ATTR_NODIRATIME)
+#define FSMOUNT_VALID_FLAGS                                                    \
+       (MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID | MOUNT_ATTR_NODEV |            \
+        MOUNT_ATTR_NOEXEC | MOUNT_ATTR__ATIME | MOUNT_ATTR_NODIRATIME |       \
+        MOUNT_ATTR_NOSYMFOLLOW)
 
 #define MOUNT_SETATTR_VALID_FLAGS (FSMOUNT_VALID_FLAGS | MOUNT_ATTR_IDMAP)
 
@@ -3487,6 +3571,8 @@ static unsigned int attr_flags_to_mnt_flags(u64 attr_flags)
                mnt_flags |= MNT_NOEXEC;
        if (attr_flags & MOUNT_ATTR_NODIRATIME)
                mnt_flags |= MNT_NODIRATIME;
+       if (attr_flags & MOUNT_ATTR_NOSYMFOLLOW)
+               mnt_flags |= MNT_NOSYMFOLLOW;
 
        return mnt_flags;
 }
@@ -3560,9 +3646,8 @@ SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags,
        if (fc->phase != FS_CONTEXT_AWAITING_MOUNT)
                goto err_unlock;
 
-       ret = -EPERM;
-       if ((fc->sb_flags & SB_MANDLOCK) && !may_mandlock())
-               goto err_unlock;
+       if (fc->sb_flags & SB_MANDLOCK)
+               warn_mandlock();
 
        newmount.mnt = vfs_create_mount(fc);
        if (IS_ERR(newmount.mnt)) {
@@ -3666,7 +3751,10 @@ SYSCALL_DEFINE5(move_mount,
        if (ret < 0)
                goto out_to;
 
-       ret = do_move_mount(&from_path, &to_path);
+       if (flags & MOVE_MOUNT_SET_GROUP)
+               ret = do_set_group(&from_path, &to_path);
+       else
+               ret = do_move_mount(&from_path, &to_path);
 
 out_to:
        path_put(&to_path);
@@ -4219,7 +4307,7 @@ void __init mnt_init(void)
        int err;
 
        mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount),
-                       0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
+                       0, SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT, NULL);
 
        mount_hashtable = alloc_large_system_hash("Mount-cache",
                                sizeof(struct hlist_head),