|
@@ -1540,8 +1540,13 @@ static int do_umount(struct mount *mnt, int flags)
|
|
|
|
|
|
namespace_lock();
|
|
|
lock_mount_hash();
|
|
|
- event++;
|
|
|
|
|
|
+ /* Recheck MNT_LOCKED with the locks held */
|
|
|
+ retval = -EINVAL;
|
|
|
+ if (mnt->mnt.mnt_flags & MNT_LOCKED)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ event++;
|
|
|
if (flags & MNT_DETACH) {
|
|
|
if (!list_empty(&mnt->mnt_list))
|
|
|
umount_tree(mnt, UMOUNT_PROPAGATE);
|
|
@@ -1555,6 +1560,7 @@ static int do_umount(struct mount *mnt, int flags)
|
|
|
retval = 0;
|
|
|
}
|
|
|
}
|
|
|
+out:
|
|
|
unlock_mount_hash();
|
|
|
namespace_unlock();
|
|
|
return retval;
|
|
@@ -1645,7 +1651,7 @@ int ksys_umount(char __user *name, int flags)
|
|
|
goto dput_and_out;
|
|
|
if (!check_mnt(mnt))
|
|
|
goto dput_and_out;
|
|
|
- if (mnt->mnt.mnt_flags & MNT_LOCKED)
|
|
|
+ if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */
|
|
|
goto dput_and_out;
|
|
|
retval = -EPERM;
|
|
|
if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN))
|
|
@@ -1728,8 +1734,14 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
|
|
|
for (s = r; s; s = next_mnt(s, r)) {
|
|
|
if (!(flag & CL_COPY_UNBINDABLE) &&
|
|
|
IS_MNT_UNBINDABLE(s)) {
|
|
|
- s = skip_mnt_tree(s);
|
|
|
- continue;
|
|
|
+ if (s->mnt.mnt_flags & MNT_LOCKED) {
|
|
|
+ /* Both unbindable and locked. */
|
|
|
+ q = ERR_PTR(-EPERM);
|
|
|
+ goto out;
|
|
|
+ } else {
|
|
|
+ s = skip_mnt_tree(s);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
}
|
|
|
if (!(flag & CL_COPY_MNT_NS_FILE) &&
|
|
|
is_mnt_ns_file(s->mnt.mnt_root)) {
|
|
@@ -1782,7 +1794,7 @@ void drop_collected_mounts(struct vfsmount *mnt)
|
|
|
{
|
|
|
namespace_lock();
|
|
|
lock_mount_hash();
|
|
|
- umount_tree(real_mount(mnt), UMOUNT_SYNC);
|
|
|
+ umount_tree(real_mount(mnt), 0);
|
|
|
unlock_mount_hash();
|
|
|
namespace_unlock();
|
|
|
}
|