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, |
