Commit 1de4f2ef authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace

Pull namespace fixes from Eric Biederman:
 "I believe all of these are simple obviously correct bug fixes. These
  fall into two groups:

   - Fixing the implementation of MNT_LOCKED which prevents lesser
     privileged users from seeing unders mounts created by more
     privileged users.

   - Fixing the extended uid and group mapping in user namespaces.

  As well as ensuring the code looks correct I have spot tested these
  changes as well and in my testing the fixes are working"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
  mount: Prevent MNT_DETACH from disconnecting locked mounts
  mount: Don't allow copying MNT_UNBINDABLE|MNT_LOCKED mounts
  mount: Retest MNT_LOCKED in do_umount
  userns: also map extents in the reverse map to kernel IDs
parents a1aa42f1 9c8e0a1b
...@@ -1540,8 +1540,13 @@ static int do_umount(struct mount *mnt, int flags) ...@@ -1540,8 +1540,13 @@ static int do_umount(struct mount *mnt, int flags)
namespace_lock(); namespace_lock();
lock_mount_hash(); 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 (flags & MNT_DETACH) {
if (!list_empty(&mnt->mnt_list)) if (!list_empty(&mnt->mnt_list))
umount_tree(mnt, UMOUNT_PROPAGATE); umount_tree(mnt, UMOUNT_PROPAGATE);
...@@ -1555,6 +1560,7 @@ static int do_umount(struct mount *mnt, int flags) ...@@ -1555,6 +1560,7 @@ static int do_umount(struct mount *mnt, int flags)
retval = 0; retval = 0;
} }
} }
out:
unlock_mount_hash(); unlock_mount_hash();
namespace_unlock(); namespace_unlock();
return retval; return retval;
...@@ -1645,7 +1651,7 @@ int ksys_umount(char __user *name, int flags) ...@@ -1645,7 +1651,7 @@ int ksys_umount(char __user *name, int flags)
goto dput_and_out; goto dput_and_out;
if (!check_mnt(mnt)) if (!check_mnt(mnt))
goto dput_and_out; goto dput_and_out;
if (mnt->mnt.mnt_flags & MNT_LOCKED) if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */
goto dput_and_out; goto dput_and_out;
retval = -EPERM; retval = -EPERM;
if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN)) if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN))
...@@ -1728,8 +1734,14 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, ...@@ -1728,8 +1734,14 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
for (s = r; s; s = next_mnt(s, r)) { for (s = r; s; s = next_mnt(s, r)) {
if (!(flag & CL_COPY_UNBINDABLE) && if (!(flag & CL_COPY_UNBINDABLE) &&
IS_MNT_UNBINDABLE(s)) { IS_MNT_UNBINDABLE(s)) {
s = skip_mnt_tree(s); if (s->mnt.mnt_flags & MNT_LOCKED) {
continue; /* Both unbindable and locked. */
q = ERR_PTR(-EPERM);
goto out;
} else {
s = skip_mnt_tree(s);
continue;
}
} }
if (!(flag & CL_COPY_MNT_NS_FILE) && if (!(flag & CL_COPY_MNT_NS_FILE) &&
is_mnt_ns_file(s->mnt.mnt_root)) { is_mnt_ns_file(s->mnt.mnt_root)) {
...@@ -1782,7 +1794,7 @@ void drop_collected_mounts(struct vfsmount *mnt) ...@@ -1782,7 +1794,7 @@ void drop_collected_mounts(struct vfsmount *mnt)
{ {
namespace_lock(); namespace_lock();
lock_mount_hash(); lock_mount_hash();
umount_tree(real_mount(mnt), UMOUNT_SYNC); umount_tree(real_mount(mnt), 0);
unlock_mount_hash(); unlock_mount_hash();
namespace_unlock(); namespace_unlock();
} }
......
...@@ -974,10 +974,6 @@ static ssize_t map_write(struct file *file, const char __user *buf, ...@@ -974,10 +974,6 @@ static ssize_t map_write(struct file *file, const char __user *buf,
if (!new_idmap_permitted(file, ns, cap_setid, &new_map)) if (!new_idmap_permitted(file, ns, cap_setid, &new_map))
goto out; goto out;
ret = sort_idmaps(&new_map);
if (ret < 0)
goto out;
ret = -EPERM; ret = -EPERM;
/* Map the lower ids from the parent user namespace to the /* Map the lower ids from the parent user namespace to the
* kernel global id space. * kernel global id space.
...@@ -1004,6 +1000,14 @@ static ssize_t map_write(struct file *file, const char __user *buf, ...@@ -1004,6 +1000,14 @@ static ssize_t map_write(struct file *file, const char __user *buf,
e->lower_first = lower_first; e->lower_first = lower_first;
} }
/*
* If we want to use binary search for lookup, this clones the extent
* array and sorts both copies.
*/
ret = sort_idmaps(&new_map);
if (ret < 0)
goto out;
/* Install the map */ /* Install the map */
if (new_map.nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS) { if (new_map.nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS) {
memcpy(map->extent, new_map.extent, memcpy(map->extent, new_map.extent,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment