diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-11-10 14:27:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-11-10 14:27:58 -0500 |
commit | 1de4f2ef216dade3b5bd5f5247c4c750a953f51c (patch) | |
tree | 7be22ffabcb98c2aeeb0df644a32a06328154c2f | |
parent | a1aa42f1d8c00a0767afee28d17caafd2a4dd8ff (diff) | |
parent | 9c8e0a1b683525464a2abe9fb4b54404a50ed2b4 (diff) |
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
-rw-r--r-- | fs/namespace.c | 22 | ||||
-rw-r--r-- | kernel/user_namespace.c | 12 |
2 files changed, 25 insertions, 9 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 98d27da43304..74f64294a410 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1540,8 +1540,13 @@ static int do_umount(struct mount *mnt, int flags) | |||
1540 | 1540 | ||
1541 | namespace_lock(); | 1541 | namespace_lock(); |
1542 | lock_mount_hash(); | 1542 | lock_mount_hash(); |
1543 | event++; | ||
1544 | 1543 | ||
1544 | /* Recheck MNT_LOCKED with the locks held */ | ||
1545 | retval = -EINVAL; | ||
1546 | if (mnt->mnt.mnt_flags & MNT_LOCKED) | ||
1547 | goto out; | ||
1548 | |||
1549 | event++; | ||
1545 | if (flags & MNT_DETACH) { | 1550 | if (flags & MNT_DETACH) { |
1546 | if (!list_empty(&mnt->mnt_list)) | 1551 | if (!list_empty(&mnt->mnt_list)) |
1547 | umount_tree(mnt, UMOUNT_PROPAGATE); | 1552 | umount_tree(mnt, UMOUNT_PROPAGATE); |
@@ -1555,6 +1560,7 @@ static int do_umount(struct mount *mnt, int flags) | |||
1555 | retval = 0; | 1560 | retval = 0; |
1556 | } | 1561 | } |
1557 | } | 1562 | } |
1563 | out: | ||
1558 | unlock_mount_hash(); | 1564 | unlock_mount_hash(); |
1559 | namespace_unlock(); | 1565 | namespace_unlock(); |
1560 | return retval; | 1566 | return retval; |
@@ -1645,7 +1651,7 @@ int ksys_umount(char __user *name, int flags) | |||
1645 | goto dput_and_out; | 1651 | goto dput_and_out; |
1646 | if (!check_mnt(mnt)) | 1652 | if (!check_mnt(mnt)) |
1647 | goto dput_and_out; | 1653 | goto dput_and_out; |
1648 | if (mnt->mnt.mnt_flags & MNT_LOCKED) | 1654 | if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */ |
1649 | goto dput_and_out; | 1655 | goto dput_and_out; |
1650 | retval = -EPERM; | 1656 | retval = -EPERM; |
1651 | if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN)) | 1657 | if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN)) |
@@ -1728,8 +1734,14 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, | |||
1728 | for (s = r; s; s = next_mnt(s, r)) { | 1734 | for (s = r; s; s = next_mnt(s, r)) { |
1729 | if (!(flag & CL_COPY_UNBINDABLE) && | 1735 | if (!(flag & CL_COPY_UNBINDABLE) && |
1730 | IS_MNT_UNBINDABLE(s)) { | 1736 | IS_MNT_UNBINDABLE(s)) { |
1731 | s = skip_mnt_tree(s); | 1737 | if (s->mnt.mnt_flags & MNT_LOCKED) { |
1732 | continue; | 1738 | /* Both unbindable and locked. */ |
1739 | q = ERR_PTR(-EPERM); | ||
1740 | goto out; | ||
1741 | } else { | ||
1742 | s = skip_mnt_tree(s); | ||
1743 | continue; | ||
1744 | } | ||
1733 | } | 1745 | } |
1734 | if (!(flag & CL_COPY_MNT_NS_FILE) && | 1746 | if (!(flag & CL_COPY_MNT_NS_FILE) && |
1735 | is_mnt_ns_file(s->mnt.mnt_root)) { | 1747 | is_mnt_ns_file(s->mnt.mnt_root)) { |
@@ -1782,7 +1794,7 @@ void drop_collected_mounts(struct vfsmount *mnt) | |||
1782 | { | 1794 | { |
1783 | namespace_lock(); | 1795 | namespace_lock(); |
1784 | lock_mount_hash(); | 1796 | lock_mount_hash(); |
1785 | umount_tree(real_mount(mnt), UMOUNT_SYNC); | 1797 | umount_tree(real_mount(mnt), 0); |
1786 | unlock_mount_hash(); | 1798 | unlock_mount_hash(); |
1787 | namespace_unlock(); | 1799 | namespace_unlock(); |
1788 | } | 1800 | } |
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index e5222b5fb4fe..923414a246e9 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
@@ -974,10 +974,6 @@ static ssize_t map_write(struct file *file, const char __user *buf, | |||
974 | if (!new_idmap_permitted(file, ns, cap_setid, &new_map)) | 974 | if (!new_idmap_permitted(file, ns, cap_setid, &new_map)) |
975 | goto out; | 975 | goto out; |
976 | 976 | ||
977 | ret = sort_idmaps(&new_map); | ||
978 | if (ret < 0) | ||
979 | goto out; | ||
980 | |||
981 | ret = -EPERM; | 977 | ret = -EPERM; |
982 | /* Map the lower ids from the parent user namespace to the | 978 | /* Map the lower ids from the parent user namespace to the |
983 | * kernel global id space. | 979 | * kernel global id space. |
@@ -1004,6 +1000,14 @@ static ssize_t map_write(struct file *file, const char __user *buf, | |||
1004 | e->lower_first = lower_first; | 1000 | e->lower_first = lower_first; |
1005 | } | 1001 | } |
1006 | 1002 | ||
1003 | /* | ||
1004 | * If we want to use binary search for lookup, this clones the extent | ||
1005 | * array and sorts both copies. | ||
1006 | */ | ||
1007 | ret = sort_idmaps(&new_map); | ||
1008 | if (ret < 0) | ||
1009 | goto out; | ||
1010 | |||
1007 | /* Install the map */ | 1011 | /* Install the map */ |
1008 | if (new_map.nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS) { | 1012 | if (new_map.nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS) { |
1009 | memcpy(map->extent, new_map.extent, | 1013 | memcpy(map->extent, new_map.extent, |