Merge tag 'pm+acpi-3.19-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[cascardo/linux.git] / fs / namespace.c
index 30df6e7..cd1e968 100644 (file)
@@ -963,7 +963,8 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
        }
 
        /* Don't allow unprivileged users to reveal what is under a mount */
-       if ((flag & CL_UNPRIVILEGED) && list_empty(&old->mnt_expire))
+       if ((flag & CL_UNPRIVILEGED) &&
+           (!(flag & CL_EXPIRE) || list_empty(&old->mnt_expire)))
                mnt->mnt.mnt_flags |= MNT_LOCKED;
 
        atomic_inc(&sb->s_active);
@@ -1369,6 +1370,8 @@ void umount_tree(struct mount *mnt, int how)
        }
        if (last) {
                last->mnt_hash.next = unmounted.first;
+               if (unmounted.first)
+                       unmounted.first->pprev = &last->mnt_hash.next;
                unmounted.first = tmp_list.first;
                unmounted.first->pprev = &unmounted.first;
        }
@@ -1544,6 +1547,9 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
                goto dput_and_out;
        if (mnt->mnt.mnt_flags & MNT_LOCKED)
                goto dput_and_out;
+       retval = -EPERM;
+       if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN))
+               goto dput_and_out;
 
        retval = do_umount(mnt, flags);
 dput_and_out:
@@ -1606,7 +1612,6 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
        if (IS_ERR(q))
                return q;
 
-       q->mnt.mnt_flags &= ~MNT_LOCKED;
        q->mnt_mountpoint = mnt->mnt_mountpoint;
 
        p = mnt;
@@ -2097,7 +2102,13 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
        }
        if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) &&
            !(mnt_flags & MNT_NODEV)) {
-               return -EPERM;
+               /* Was the nodev implicitly added in mount? */
+               if ((mnt->mnt_ns->user_ns != &init_user_ns) &&
+                   !(sb->s_type->fs_flags & FS_USERNS_DEV_MOUNT)) {
+                       mnt_flags |= MNT_NODEV;
+               } else {
+                       return -EPERM;
+               }
        }
        if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) &&
            !(mnt_flags & MNT_NOSUID)) {
@@ -2958,6 +2969,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
        /* mount new_root on / */
        attach_mnt(new_mnt, real_mount(root_parent.mnt), root_mp);
        touch_mnt_namespace(current->nsproxy->mnt_ns);
+       /* A moved mount should not expire automatically */
+       list_del_init(&new_mnt->mnt_expire);
        unlock_mount_hash();
        chroot_fs_refs(&root, &new);
        put_mountpoint(root_mp);
@@ -3002,6 +3015,7 @@ static void __init init_mount_tree(void)
 
        root.mnt = mnt;
        root.dentry = mnt->mnt_root;
+       mnt->mnt_flags |= MNT_LOCKED;
 
        set_fs_pwd(current->fs, &root);
        set_fs_root(current->fs, &root);