diff options
-rw-r--r-- | fs/namespace.c | 121 | ||||
-rw-r--r-- | fs/open.c | 2 | ||||
-rw-r--r-- | fs/pnode.h | 5 | ||||
-rw-r--r-- | fs/proc/root.c | 6 | ||||
-rw-r--r-- | fs/sysfs/mount.c | 11 | ||||
-rw-r--r-- | include/linux/capability.h | 1 | ||||
-rw-r--r-- | include/linux/fs.h | 1 | ||||
-rw-r--r-- | include/linux/kobject_ns.h | 2 | ||||
-rw-r--r-- | include/linux/mount.h | 1 | ||||
-rw-r--r-- | include/linux/user_namespace.h | 4 | ||||
-rw-r--r-- | ipc/namespace.c | 2 | ||||
-rw-r--r-- | kernel/capability.c | 12 | ||||
-rw-r--r-- | kernel/fork.c | 5 | ||||
-rw-r--r-- | kernel/groups.c | 2 | ||||
-rw-r--r-- | kernel/nsproxy.c | 36 | ||||
-rw-r--r-- | kernel/pid.c | 1 | ||||
-rw-r--r-- | kernel/pid_namespace.c | 2 | ||||
-rw-r--r-- | kernel/sys.c | 20 | ||||
-rw-r--r-- | kernel/uid16.c | 2 | ||||
-rw-r--r-- | kernel/user.c | 2 | ||||
-rw-r--r-- | kernel/user_namespace.c | 2 | ||||
-rw-r--r-- | kernel/utsname.c | 2 | ||||
-rw-r--r-- | lib/kobject.c | 15 | ||||
-rw-r--r-- | net/core/net-sysfs.c | 8 | ||||
-rw-r--r-- | net/core/net_namespace.c | 2 | ||||
-rw-r--r-- | net/core/scm.c | 4 | ||||
-rw-r--r-- | security/commoncap.c | 10 |
27 files changed, 177 insertions, 104 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index ad8ea9bc2518..ef69fa5d2e5b 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -831,6 +831,10 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, | |||
831 | if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY)) | 831 | if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY)) |
832 | mnt->mnt.mnt_flags |= MNT_LOCK_READONLY; | 832 | mnt->mnt.mnt_flags |= MNT_LOCK_READONLY; |
833 | 833 | ||
834 | /* Don't allow unprivileged users to reveal what is under a mount */ | ||
835 | if ((flag & CL_UNPRIVILEGED) && list_empty(&old->mnt_expire)) | ||
836 | mnt->mnt.mnt_flags |= MNT_LOCKED; | ||
837 | |||
834 | atomic_inc(&sb->s_active); | 838 | atomic_inc(&sb->s_active); |
835 | mnt->mnt.mnt_sb = sb; | 839 | mnt->mnt.mnt_sb = sb; |
836 | mnt->mnt.mnt_root = dget(root); | 840 | mnt->mnt.mnt_root = dget(root); |
@@ -1327,6 +1331,8 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) | |||
1327 | goto dput_and_out; | 1331 | goto dput_and_out; |
1328 | if (!check_mnt(mnt)) | 1332 | if (!check_mnt(mnt)) |
1329 | goto dput_and_out; | 1333 | goto dput_and_out; |
1334 | if (mnt->mnt.mnt_flags & MNT_LOCKED) | ||
1335 | goto dput_and_out; | ||
1330 | 1336 | ||
1331 | retval = do_umount(mnt, flags); | 1337 | retval = do_umount(mnt, flags); |
1332 | dput_and_out: | 1338 | dput_and_out: |
@@ -1349,14 +1355,11 @@ SYSCALL_DEFINE1(oldumount, char __user *, name) | |||
1349 | 1355 | ||
1350 | #endif | 1356 | #endif |
1351 | 1357 | ||
1352 | static bool mnt_ns_loop(struct path *path) | 1358 | static bool is_mnt_ns_file(struct dentry *dentry) |
1353 | { | 1359 | { |
1354 | /* Could bind mounting the mount namespace inode cause a | 1360 | /* Is this a proxy for a mount namespace? */ |
1355 | * mount namespace loop? | 1361 | struct inode *inode = dentry->d_inode; |
1356 | */ | ||
1357 | struct inode *inode = path->dentry->d_inode; | ||
1358 | struct proc_ns *ei; | 1362 | struct proc_ns *ei; |
1359 | struct mnt_namespace *mnt_ns; | ||
1360 | 1363 | ||
1361 | if (!proc_ns_inode(inode)) | 1364 | if (!proc_ns_inode(inode)) |
1362 | return false; | 1365 | return false; |
@@ -1365,7 +1368,19 @@ static bool mnt_ns_loop(struct path *path) | |||
1365 | if (ei->ns_ops != &mntns_operations) | 1368 | if (ei->ns_ops != &mntns_operations) |
1366 | return false; | 1369 | return false; |
1367 | 1370 | ||
1368 | mnt_ns = ei->ns; | 1371 | return true; |
1372 | } | ||
1373 | |||
1374 | static bool mnt_ns_loop(struct dentry *dentry) | ||
1375 | { | ||
1376 | /* Could bind mounting the mount namespace inode cause a | ||
1377 | * mount namespace loop? | ||
1378 | */ | ||
1379 | struct mnt_namespace *mnt_ns; | ||
1380 | if (!is_mnt_ns_file(dentry)) | ||
1381 | return false; | ||
1382 | |||
1383 | mnt_ns = get_proc_ns(dentry->d_inode)->ns; | ||
1369 | return current->nsproxy->mnt_ns->seq >= mnt_ns->seq; | 1384 | return current->nsproxy->mnt_ns->seq >= mnt_ns->seq; |
1370 | } | 1385 | } |
1371 | 1386 | ||
@@ -1374,13 +1389,17 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, | |||
1374 | { | 1389 | { |
1375 | struct mount *res, *p, *q, *r, *parent; | 1390 | struct mount *res, *p, *q, *r, *parent; |
1376 | 1391 | ||
1377 | if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt)) | 1392 | if (!(flag & CL_COPY_UNBINDABLE) && IS_MNT_UNBINDABLE(mnt)) |
1393 | return ERR_PTR(-EINVAL); | ||
1394 | |||
1395 | if (!(flag & CL_COPY_MNT_NS_FILE) && is_mnt_ns_file(dentry)) | ||
1378 | return ERR_PTR(-EINVAL); | 1396 | return ERR_PTR(-EINVAL); |
1379 | 1397 | ||
1380 | res = q = clone_mnt(mnt, dentry, flag); | 1398 | res = q = clone_mnt(mnt, dentry, flag); |
1381 | if (IS_ERR(q)) | 1399 | if (IS_ERR(q)) |
1382 | return q; | 1400 | return q; |
1383 | 1401 | ||
1402 | q->mnt.mnt_flags &= ~MNT_LOCKED; | ||
1384 | q->mnt_mountpoint = mnt->mnt_mountpoint; | 1403 | q->mnt_mountpoint = mnt->mnt_mountpoint; |
1385 | 1404 | ||
1386 | p = mnt; | 1405 | p = mnt; |
@@ -1390,7 +1409,13 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, | |||
1390 | continue; | 1409 | continue; |
1391 | 1410 | ||
1392 | for (s = r; s; s = next_mnt(s, r)) { | 1411 | for (s = r; s; s = next_mnt(s, r)) { |
1393 | if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(s)) { | 1412 | if (!(flag & CL_COPY_UNBINDABLE) && |
1413 | IS_MNT_UNBINDABLE(s)) { | ||
1414 | s = skip_mnt_tree(s); | ||
1415 | continue; | ||
1416 | } | ||
1417 | if (!(flag & CL_COPY_MNT_NS_FILE) && | ||
1418 | is_mnt_ns_file(s->mnt.mnt_root)) { | ||
1394 | s = skip_mnt_tree(s); | 1419 | s = skip_mnt_tree(s); |
1395 | continue; | 1420 | continue; |
1396 | } | 1421 | } |
@@ -1696,6 +1721,19 @@ static int do_change_type(struct path *path, int flag) | |||
1696 | return err; | 1721 | return err; |
1697 | } | 1722 | } |
1698 | 1723 | ||
1724 | static bool has_locked_children(struct mount *mnt, struct dentry *dentry) | ||
1725 | { | ||
1726 | struct mount *child; | ||
1727 | list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { | ||
1728 | if (!is_subdir(child->mnt_mountpoint, dentry)) | ||
1729 | continue; | ||
1730 | |||
1731 | if (child->mnt.mnt_flags & MNT_LOCKED) | ||
1732 | return true; | ||
1733 | } | ||
1734 | return false; | ||
1735 | } | ||
1736 | |||
1699 | /* | 1737 | /* |
1700 | * do loopback mount. | 1738 | * do loopback mount. |
1701 | */ | 1739 | */ |
@@ -1713,7 +1751,7 @@ static int do_loopback(struct path *path, const char *old_name, | |||
1713 | return err; | 1751 | return err; |
1714 | 1752 | ||
1715 | err = -EINVAL; | 1753 | err = -EINVAL; |
1716 | if (mnt_ns_loop(&old_path)) | 1754 | if (mnt_ns_loop(old_path.dentry)) |
1717 | goto out; | 1755 | goto out; |
1718 | 1756 | ||
1719 | mp = lock_mount(path); | 1757 | mp = lock_mount(path); |
@@ -1731,8 +1769,11 @@ static int do_loopback(struct path *path, const char *old_name, | |||
1731 | if (!check_mnt(parent) || !check_mnt(old)) | 1769 | if (!check_mnt(parent) || !check_mnt(old)) |
1732 | goto out2; | 1770 | goto out2; |
1733 | 1771 | ||
1772 | if (!recurse && has_locked_children(old, old_path.dentry)) | ||
1773 | goto out2; | ||
1774 | |||
1734 | if (recurse) | 1775 | if (recurse) |
1735 | mnt = copy_tree(old, old_path.dentry, 0); | 1776 | mnt = copy_tree(old, old_path.dentry, CL_COPY_MNT_NS_FILE); |
1736 | else | 1777 | else |
1737 | mnt = clone_mnt(old, old_path.dentry, 0); | 1778 | mnt = clone_mnt(old, old_path.dentry, 0); |
1738 | 1779 | ||
@@ -1741,6 +1782,8 @@ static int do_loopback(struct path *path, const char *old_name, | |||
1741 | goto out2; | 1782 | goto out2; |
1742 | } | 1783 | } |
1743 | 1784 | ||
1785 | mnt->mnt.mnt_flags &= ~MNT_LOCKED; | ||
1786 | |||
1744 | err = graft_tree(mnt, parent, mp); | 1787 | err = graft_tree(mnt, parent, mp); |
1745 | if (err) { | 1788 | if (err) { |
1746 | br_write_lock(&vfsmount_lock); | 1789 | br_write_lock(&vfsmount_lock); |
@@ -1853,6 +1896,9 @@ static int do_move_mount(struct path *path, const char *old_name) | |||
1853 | if (!check_mnt(p) || !check_mnt(old)) | 1896 | if (!check_mnt(p) || !check_mnt(old)) |
1854 | goto out1; | 1897 | goto out1; |
1855 | 1898 | ||
1899 | if (old->mnt.mnt_flags & MNT_LOCKED) | ||
1900 | goto out1; | ||
1901 | |||
1856 | err = -EINVAL; | 1902 | err = -EINVAL; |
1857 | if (old_path.dentry != old_path.mnt->mnt_root) | 1903 | if (old_path.dentry != old_path.mnt->mnt_root) |
1858 | goto out1; | 1904 | goto out1; |
@@ -2389,7 +2435,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2389 | 2435 | ||
2390 | namespace_lock(); | 2436 | namespace_lock(); |
2391 | /* First pass: copy the tree topology */ | 2437 | /* First pass: copy the tree topology */ |
2392 | copy_flags = CL_COPY_ALL | CL_EXPIRE; | 2438 | copy_flags = CL_COPY_UNBINDABLE | CL_EXPIRE; |
2393 | if (user_ns != mnt_ns->user_ns) | 2439 | if (user_ns != mnt_ns->user_ns) |
2394 | copy_flags |= CL_SHARED_TO_SLAVE | CL_UNPRIVILEGED; | 2440 | copy_flags |= CL_SHARED_TO_SLAVE | CL_UNPRIVILEGED; |
2395 | new = copy_tree(old, old->mnt.mnt_root, copy_flags); | 2441 | new = copy_tree(old, old->mnt.mnt_root, copy_flags); |
@@ -2424,6 +2470,10 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2424 | } | 2470 | } |
2425 | p = next_mnt(p, old); | 2471 | p = next_mnt(p, old); |
2426 | q = next_mnt(q, new); | 2472 | q = next_mnt(q, new); |
2473 | if (!q) | ||
2474 | break; | ||
2475 | while (p->mnt.mnt_root != q->mnt.mnt_root) | ||
2476 | p = next_mnt(p, old); | ||
2427 | } | 2477 | } |
2428 | namespace_unlock(); | 2478 | namespace_unlock(); |
2429 | 2479 | ||
@@ -2630,6 +2680,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, | |||
2630 | goto out4; | 2680 | goto out4; |
2631 | if (!check_mnt(root_mnt) || !check_mnt(new_mnt)) | 2681 | if (!check_mnt(root_mnt) || !check_mnt(new_mnt)) |
2632 | goto out4; | 2682 | goto out4; |
2683 | if (new_mnt->mnt.mnt_flags & MNT_LOCKED) | ||
2684 | goto out4; | ||
2633 | error = -ENOENT; | 2685 | error = -ENOENT; |
2634 | if (d_unlinked(new.dentry)) | 2686 | if (d_unlinked(new.dentry)) |
2635 | goto out4; | 2687 | goto out4; |
@@ -2653,6 +2705,10 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, | |||
2653 | br_write_lock(&vfsmount_lock); | 2705 | br_write_lock(&vfsmount_lock); |
2654 | detach_mnt(new_mnt, &parent_path); | 2706 | detach_mnt(new_mnt, &parent_path); |
2655 | detach_mnt(root_mnt, &root_parent); | 2707 | detach_mnt(root_mnt, &root_parent); |
2708 | if (root_mnt->mnt.mnt_flags & MNT_LOCKED) { | ||
2709 | new_mnt->mnt.mnt_flags |= MNT_LOCKED; | ||
2710 | root_mnt->mnt.mnt_flags &= ~MNT_LOCKED; | ||
2711 | } | ||
2656 | /* mount old root on put_old */ | 2712 | /* mount old root on put_old */ |
2657 | attach_mnt(root_mnt, old_mnt, old_mp); | 2713 | attach_mnt(root_mnt, old_mnt, old_mp); |
2658 | /* mount new_root on / */ | 2714 | /* mount new_root on / */ |
@@ -2811,25 +2867,38 @@ bool current_chrooted(void) | |||
2811 | return chrooted; | 2867 | return chrooted; |
2812 | } | 2868 | } |
2813 | 2869 | ||
2814 | void update_mnt_policy(struct user_namespace *userns) | 2870 | bool fs_fully_visible(struct file_system_type *type) |
2815 | { | 2871 | { |
2816 | struct mnt_namespace *ns = current->nsproxy->mnt_ns; | 2872 | struct mnt_namespace *ns = current->nsproxy->mnt_ns; |
2817 | struct mount *mnt; | 2873 | struct mount *mnt; |
2874 | bool visible = false; | ||
2818 | 2875 | ||
2819 | down_read(&namespace_sem); | 2876 | if (unlikely(!ns)) |
2877 | return false; | ||
2878 | |||
2879 | namespace_lock(); | ||
2820 | list_for_each_entry(mnt, &ns->list, mnt_list) { | 2880 | list_for_each_entry(mnt, &ns->list, mnt_list) { |
2821 | switch (mnt->mnt.mnt_sb->s_magic) { | 2881 | struct mount *child; |
2822 | case SYSFS_MAGIC: | 2882 | if (mnt->mnt.mnt_sb->s_type != type) |
2823 | userns->may_mount_sysfs = true; | 2883 | continue; |
2824 | break; | 2884 | |
2825 | case PROC_SUPER_MAGIC: | 2885 | /* This mount is not fully visible if there are any child mounts |
2826 | userns->may_mount_proc = true; | 2886 | * that cover anything except for empty directories. |
2827 | break; | 2887 | */ |
2888 | list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { | ||
2889 | struct inode *inode = child->mnt_mountpoint->d_inode; | ||
2890 | if (!S_ISDIR(inode->i_mode)) | ||
2891 | goto next; | ||
2892 | if (inode->i_nlink != 2) | ||
2893 | goto next; | ||
2828 | } | 2894 | } |
2829 | if (userns->may_mount_sysfs && userns->may_mount_proc) | 2895 | visible = true; |
2830 | break; | 2896 | goto found; |
2897 | next: ; | ||
2831 | } | 2898 | } |
2832 | up_read(&namespace_sem); | 2899 | found: |
2900 | namespace_unlock(); | ||
2901 | return visible; | ||
2833 | } | 2902 | } |
2834 | 2903 | ||
2835 | static void *mntns_get(struct task_struct *task) | 2904 | static void *mntns_get(struct task_struct *task) |
@@ -2860,8 +2929,8 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns) | |||
2860 | struct path root; | 2929 | struct path root; |
2861 | 2930 | ||
2862 | if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) || | 2931 | if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) || |
2863 | !nsown_capable(CAP_SYS_CHROOT) || | 2932 | !ns_capable(current_user_ns(), CAP_SYS_CHROOT) || |
2864 | !nsown_capable(CAP_SYS_ADMIN)) | 2933 | !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) |
2865 | return -EPERM; | 2934 | return -EPERM; |
2866 | 2935 | ||
2867 | if (fs->users != 1) | 2936 | if (fs->users != 1) |
@@ -443,7 +443,7 @@ retry: | |||
443 | goto dput_and_out; | 443 | goto dput_and_out; |
444 | 444 | ||
445 | error = -EPERM; | 445 | error = -EPERM; |
446 | if (!nsown_capable(CAP_SYS_CHROOT)) | 446 | if (!ns_capable(current_user_ns(), CAP_SYS_CHROOT)) |
447 | goto dput_and_out; | 447 | goto dput_and_out; |
448 | error = security_path_chroot(&path); | 448 | error = security_path_chroot(&path); |
449 | if (error) | 449 | if (error) |
diff --git a/fs/pnode.h b/fs/pnode.h index b091445c1c4a..59e7eda1851e 100644 --- a/fs/pnode.h +++ b/fs/pnode.h | |||
@@ -19,11 +19,14 @@ | |||
19 | 19 | ||
20 | #define CL_EXPIRE 0x01 | 20 | #define CL_EXPIRE 0x01 |
21 | #define CL_SLAVE 0x02 | 21 | #define CL_SLAVE 0x02 |
22 | #define CL_COPY_ALL 0x04 | 22 | #define CL_COPY_UNBINDABLE 0x04 |
23 | #define CL_MAKE_SHARED 0x08 | 23 | #define CL_MAKE_SHARED 0x08 |
24 | #define CL_PRIVATE 0x10 | 24 | #define CL_PRIVATE 0x10 |
25 | #define CL_SHARED_TO_SLAVE 0x20 | 25 | #define CL_SHARED_TO_SLAVE 0x20 |
26 | #define CL_UNPRIVILEGED 0x40 | 26 | #define CL_UNPRIVILEGED 0x40 |
27 | #define CL_COPY_MNT_NS_FILE 0x80 | ||
28 | |||
29 | #define CL_COPY_ALL (CL_COPY_UNBINDABLE | CL_COPY_MNT_NS_FILE) | ||
27 | 30 | ||
28 | static inline void set_mnt_shared(struct mount *mnt) | 31 | static inline void set_mnt_shared(struct mount *mnt) |
29 | { | 32 | { |
diff --git a/fs/proc/root.c b/fs/proc/root.c index e0a790da726d..87dbcbef7fe4 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
@@ -110,7 +110,11 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, | |||
110 | ns = task_active_pid_ns(current); | 110 | ns = task_active_pid_ns(current); |
111 | options = data; | 111 | options = data; |
112 | 112 | ||
113 | if (!current_user_ns()->may_mount_proc) | 113 | if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) |
114 | return ERR_PTR(-EPERM); | ||
115 | |||
116 | /* Does the mounter have privilege over the pid namespace? */ | ||
117 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) | ||
114 | return ERR_PTR(-EPERM); | 118 | return ERR_PTR(-EPERM); |
115 | } | 119 | } |
116 | 120 | ||
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index fd7ce7a39f91..834ec2cdb7a3 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
@@ -112,8 +112,15 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, | |||
112 | struct super_block *sb; | 112 | struct super_block *sb; |
113 | int error; | 113 | int error; |
114 | 114 | ||
115 | if (!(flags & MS_KERNMOUNT) && !current_user_ns()->may_mount_sysfs) | 115 | if (!(flags & MS_KERNMOUNT)) { |
116 | return ERR_PTR(-EPERM); | 116 | if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) |
117 | return ERR_PTR(-EPERM); | ||
118 | |||
119 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) { | ||
120 | if (!kobj_ns_current_may_mount(type)) | ||
121 | return ERR_PTR(-EPERM); | ||
122 | } | ||
123 | } | ||
117 | 124 | ||
118 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 125 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
119 | if (!info) | 126 | if (!info) |
diff --git a/include/linux/capability.h b/include/linux/capability.h index d9a4f7f40f32..a6ee1f9a5018 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
@@ -210,7 +210,6 @@ extern bool has_ns_capability_noaudit(struct task_struct *t, | |||
210 | struct user_namespace *ns, int cap); | 210 | struct user_namespace *ns, int cap); |
211 | extern bool capable(int cap); | 211 | extern bool capable(int cap); |
212 | extern bool ns_capable(struct user_namespace *ns, int cap); | 212 | extern bool ns_capable(struct user_namespace *ns, int cap); |
213 | extern bool nsown_capable(int cap); | ||
214 | extern bool inode_capable(const struct inode *inode, int cap); | 213 | extern bool inode_capable(const struct inode *inode, int cap); |
215 | extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap); | 214 | extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap); |
216 | 215 | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index 3b4cd8296e41..529d8711baba 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1900,6 +1900,7 @@ extern int vfs_ustat(dev_t, struct kstatfs *); | |||
1900 | extern int freeze_super(struct super_block *super); | 1900 | extern int freeze_super(struct super_block *super); |
1901 | extern int thaw_super(struct super_block *super); | 1901 | extern int thaw_super(struct super_block *super); |
1902 | extern bool our_mnt(struct vfsmount *mnt); | 1902 | extern bool our_mnt(struct vfsmount *mnt); |
1903 | extern bool fs_fully_visible(struct file_system_type *); | ||
1903 | 1904 | ||
1904 | extern int current_umask(void); | 1905 | extern int current_umask(void); |
1905 | 1906 | ||
diff --git a/include/linux/kobject_ns.h b/include/linux/kobject_ns.h index f66b065a8b5f..df32d2508290 100644 --- a/include/linux/kobject_ns.h +++ b/include/linux/kobject_ns.h | |||
@@ -39,6 +39,7 @@ enum kobj_ns_type { | |||
39 | */ | 39 | */ |
40 | struct kobj_ns_type_operations { | 40 | struct kobj_ns_type_operations { |
41 | enum kobj_ns_type type; | 41 | enum kobj_ns_type type; |
42 | bool (*current_may_mount)(void); | ||
42 | void *(*grab_current_ns)(void); | 43 | void *(*grab_current_ns)(void); |
43 | const void *(*netlink_ns)(struct sock *sk); | 44 | const void *(*netlink_ns)(struct sock *sk); |
44 | const void *(*initial_ns)(void); | 45 | const void *(*initial_ns)(void); |
@@ -50,6 +51,7 @@ int kobj_ns_type_registered(enum kobj_ns_type type); | |||
50 | const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); | 51 | const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); |
51 | const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj); | 52 | const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj); |
52 | 53 | ||
54 | bool kobj_ns_current_may_mount(enum kobj_ns_type type); | ||
53 | void *kobj_ns_grab_current(enum kobj_ns_type type); | 55 | void *kobj_ns_grab_current(enum kobj_ns_type type); |
54 | const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk); | 56 | const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk); |
55 | const void *kobj_ns_initial(enum kobj_ns_type type); | 57 | const void *kobj_ns_initial(enum kobj_ns_type type); |
diff --git a/include/linux/mount.h b/include/linux/mount.h index 73005f9957ea..38cd98f112a0 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h | |||
@@ -48,6 +48,7 @@ struct mnt_namespace; | |||
48 | #define MNT_INTERNAL 0x4000 | 48 | #define MNT_INTERNAL 0x4000 |
49 | 49 | ||
50 | #define MNT_LOCK_READONLY 0x400000 | 50 | #define MNT_LOCK_READONLY 0x400000 |
51 | #define MNT_LOCKED 0x800000 | ||
51 | 52 | ||
52 | struct vfsmount { | 53 | struct vfsmount { |
53 | struct dentry *mnt_root; /* root of the mounted tree */ | 54 | struct dentry *mnt_root; /* root of the mounted tree */ |
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 14105c26a836..4db29859464f 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h | |||
@@ -27,8 +27,6 @@ struct user_namespace { | |||
27 | kuid_t owner; | 27 | kuid_t owner; |
28 | kgid_t group; | 28 | kgid_t group; |
29 | unsigned int proc_inum; | 29 | unsigned int proc_inum; |
30 | bool may_mount_sysfs; | ||
31 | bool may_mount_proc; | ||
32 | }; | 30 | }; |
33 | 31 | ||
34 | extern struct user_namespace init_user_ns; | 32 | extern struct user_namespace init_user_ns; |
@@ -85,6 +83,4 @@ static inline void put_user_ns(struct user_namespace *ns) | |||
85 | 83 | ||
86 | #endif | 84 | #endif |
87 | 85 | ||
88 | void update_mnt_policy(struct user_namespace *userns); | ||
89 | |||
90 | #endif /* _LINUX_USER_H */ | 86 | #endif /* _LINUX_USER_H */ |
diff --git a/ipc/namespace.c b/ipc/namespace.c index 7ee61bf44933..4be6581d3b7f 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c | |||
@@ -171,7 +171,7 @@ static int ipcns_install(struct nsproxy *nsproxy, void *new) | |||
171 | { | 171 | { |
172 | struct ipc_namespace *ns = new; | 172 | struct ipc_namespace *ns = new; |
173 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || | 173 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || |
174 | !nsown_capable(CAP_SYS_ADMIN)) | 174 | !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) |
175 | return -EPERM; | 175 | return -EPERM; |
176 | 176 | ||
177 | /* Ditch state from the old ipc namespace */ | 177 | /* Ditch state from the old ipc namespace */ |
diff --git a/kernel/capability.c b/kernel/capability.c index f6c2ce5701e1..6fc1c8af44df 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
@@ -433,18 +433,6 @@ bool capable(int cap) | |||
433 | EXPORT_SYMBOL(capable); | 433 | EXPORT_SYMBOL(capable); |
434 | 434 | ||
435 | /** | 435 | /** |
436 | * nsown_capable - Check superior capability to one's own user_ns | ||
437 | * @cap: The capability in question | ||
438 | * | ||
439 | * Return true if the current task has the given superior capability | ||
440 | * targeted at its own user namespace. | ||
441 | */ | ||
442 | bool nsown_capable(int cap) | ||
443 | { | ||
444 | return ns_capable(current_user_ns(), cap); | ||
445 | } | ||
446 | |||
447 | /** | ||
448 | * inode_capable - Check superior capability over inode | 436 | * inode_capable - Check superior capability over inode |
449 | * @inode: The inode in question | 437 | * @inode: The inode in question |
450 | * @cap: The capability in question | 438 | * @cap: The capability in question |
diff --git a/kernel/fork.c b/kernel/fork.c index bf46287c91a4..c9eaf2013002 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1825,11 +1825,6 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) | |||
1825 | if (unshare_flags & CLONE_NEWUSER) | 1825 | if (unshare_flags & CLONE_NEWUSER) |
1826 | unshare_flags |= CLONE_THREAD | CLONE_FS; | 1826 | unshare_flags |= CLONE_THREAD | CLONE_FS; |
1827 | /* | 1827 | /* |
1828 | * If unsharing a pid namespace must also unshare the thread. | ||
1829 | */ | ||
1830 | if (unshare_flags & CLONE_NEWPID) | ||
1831 | unshare_flags |= CLONE_THREAD; | ||
1832 | /* | ||
1833 | * If unsharing a thread from a thread group, must also unshare vm. | 1828 | * If unsharing a thread from a thread group, must also unshare vm. |
1834 | */ | 1829 | */ |
1835 | if (unshare_flags & CLONE_THREAD) | 1830 | if (unshare_flags & CLONE_THREAD) |
diff --git a/kernel/groups.c b/kernel/groups.c index 6b2588dd04ff..90cf1c38c8ea 100644 --- a/kernel/groups.c +++ b/kernel/groups.c | |||
@@ -233,7 +233,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) | |||
233 | struct group_info *group_info; | 233 | struct group_info *group_info; |
234 | int retval; | 234 | int retval; |
235 | 235 | ||
236 | if (!nsown_capable(CAP_SETGID)) | 236 | if (!ns_capable(current_user_ns(), CAP_SETGID)) |
237 | return -EPERM; | 237 | return -EPERM; |
238 | if ((unsigned)gidsetsize > NGROUPS_MAX) | 238 | if ((unsigned)gidsetsize > NGROUPS_MAX) |
239 | return -EINVAL; | 239 | return -EINVAL; |
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 997cbb951a3b..8e7811086b82 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c | |||
@@ -126,22 +126,16 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) | |||
126 | struct nsproxy *old_ns = tsk->nsproxy; | 126 | struct nsproxy *old_ns = tsk->nsproxy; |
127 | struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns); | 127 | struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns); |
128 | struct nsproxy *new_ns; | 128 | struct nsproxy *new_ns; |
129 | int err = 0; | ||
130 | 129 | ||
131 | if (!old_ns) | 130 | if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | |
131 | CLONE_NEWPID | CLONE_NEWNET)))) { | ||
132 | get_nsproxy(old_ns); | ||
132 | return 0; | 133 | return 0; |
133 | |||
134 | get_nsproxy(old_ns); | ||
135 | |||
136 | if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | | ||
137 | CLONE_NEWPID | CLONE_NEWNET))) | ||
138 | return 0; | ||
139 | |||
140 | if (!ns_capable(user_ns, CAP_SYS_ADMIN)) { | ||
141 | err = -EPERM; | ||
142 | goto out; | ||
143 | } | 134 | } |
144 | 135 | ||
136 | if (!ns_capable(user_ns, CAP_SYS_ADMIN)) | ||
137 | return -EPERM; | ||
138 | |||
145 | /* | 139 | /* |
146 | * CLONE_NEWIPC must detach from the undolist: after switching | 140 | * CLONE_NEWIPC must detach from the undolist: after switching |
147 | * to a new ipc namespace, the semaphore arrays from the old | 141 | * to a new ipc namespace, the semaphore arrays from the old |
@@ -149,22 +143,16 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) | |||
149 | * means share undolist with parent, so we must forbid using | 143 | * means share undolist with parent, so we must forbid using |
150 | * it along with CLONE_NEWIPC. | 144 | * it along with CLONE_NEWIPC. |
151 | */ | 145 | */ |
152 | if ((flags & CLONE_NEWIPC) && (flags & CLONE_SYSVSEM)) { | 146 | if ((flags & (CLONE_NEWIPC | CLONE_SYSVSEM)) == |
153 | err = -EINVAL; | 147 | (CLONE_NEWIPC | CLONE_SYSVSEM)) |
154 | goto out; | 148 | return -EINVAL; |
155 | } | ||
156 | 149 | ||
157 | new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs); | 150 | new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs); |
158 | if (IS_ERR(new_ns)) { | 151 | if (IS_ERR(new_ns)) |
159 | err = PTR_ERR(new_ns); | 152 | return PTR_ERR(new_ns); |
160 | goto out; | ||
161 | } | ||
162 | 153 | ||
163 | tsk->nsproxy = new_ns; | 154 | tsk->nsproxy = new_ns; |
164 | 155 | return 0; | |
165 | out: | ||
166 | put_nsproxy(old_ns); | ||
167 | return err; | ||
168 | } | 156 | } |
169 | 157 | ||
170 | void free_nsproxy(struct nsproxy *ns) | 158 | void free_nsproxy(struct nsproxy *ns) |
diff --git a/kernel/pid.c b/kernel/pid.c index 66505c1dfc51..ebe5e80b10f8 100644 --- a/kernel/pid.c +++ b/kernel/pid.c | |||
@@ -265,6 +265,7 @@ void free_pid(struct pid *pid) | |||
265 | struct pid_namespace *ns = upid->ns; | 265 | struct pid_namespace *ns = upid->ns; |
266 | hlist_del_rcu(&upid->pid_chain); | 266 | hlist_del_rcu(&upid->pid_chain); |
267 | switch(--ns->nr_hashed) { | 267 | switch(--ns->nr_hashed) { |
268 | case 2: | ||
268 | case 1: | 269 | case 1: |
269 | /* When all that is left in the pid namespace | 270 | /* When all that is left in the pid namespace |
270 | * is the reaper wake up the reaper. The reaper | 271 | * is the reaper wake up the reaper. The reaper |
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index 601bb361c235..42086551a24a 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c | |||
@@ -329,7 +329,7 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns) | |||
329 | struct pid_namespace *ancestor, *new = ns; | 329 | struct pid_namespace *ancestor, *new = ns; |
330 | 330 | ||
331 | if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) || | 331 | if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) || |
332 | !nsown_capable(CAP_SYS_ADMIN)) | 332 | !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) |
333 | return -EPERM; | 333 | return -EPERM; |
334 | 334 | ||
335 | /* | 335 | /* |
diff --git a/kernel/sys.c b/kernel/sys.c index 771129b299f8..c18ecca575b4 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -337,7 +337,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | |||
337 | if (rgid != (gid_t) -1) { | 337 | if (rgid != (gid_t) -1) { |
338 | if (gid_eq(old->gid, krgid) || | 338 | if (gid_eq(old->gid, krgid) || |
339 | gid_eq(old->egid, krgid) || | 339 | gid_eq(old->egid, krgid) || |
340 | nsown_capable(CAP_SETGID)) | 340 | ns_capable(old->user_ns, CAP_SETGID)) |
341 | new->gid = krgid; | 341 | new->gid = krgid; |
342 | else | 342 | else |
343 | goto error; | 343 | goto error; |
@@ -346,7 +346,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | |||
346 | if (gid_eq(old->gid, kegid) || | 346 | if (gid_eq(old->gid, kegid) || |
347 | gid_eq(old->egid, kegid) || | 347 | gid_eq(old->egid, kegid) || |
348 | gid_eq(old->sgid, kegid) || | 348 | gid_eq(old->sgid, kegid) || |
349 | nsown_capable(CAP_SETGID)) | 349 | ns_capable(old->user_ns, CAP_SETGID)) |
350 | new->egid = kegid; | 350 | new->egid = kegid; |
351 | else | 351 | else |
352 | goto error; | 352 | goto error; |
@@ -387,7 +387,7 @@ SYSCALL_DEFINE1(setgid, gid_t, gid) | |||
387 | old = current_cred(); | 387 | old = current_cred(); |
388 | 388 | ||
389 | retval = -EPERM; | 389 | retval = -EPERM; |
390 | if (nsown_capable(CAP_SETGID)) | 390 | if (ns_capable(old->user_ns, CAP_SETGID)) |
391 | new->gid = new->egid = new->sgid = new->fsgid = kgid; | 391 | new->gid = new->egid = new->sgid = new->fsgid = kgid; |
392 | else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid)) | 392 | else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid)) |
393 | new->egid = new->fsgid = kgid; | 393 | new->egid = new->fsgid = kgid; |
@@ -471,7 +471,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | |||
471 | new->uid = kruid; | 471 | new->uid = kruid; |
472 | if (!uid_eq(old->uid, kruid) && | 472 | if (!uid_eq(old->uid, kruid) && |
473 | !uid_eq(old->euid, kruid) && | 473 | !uid_eq(old->euid, kruid) && |
474 | !nsown_capable(CAP_SETUID)) | 474 | !ns_capable(old->user_ns, CAP_SETUID)) |
475 | goto error; | 475 | goto error; |
476 | } | 476 | } |
477 | 477 | ||
@@ -480,7 +480,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | |||
480 | if (!uid_eq(old->uid, keuid) && | 480 | if (!uid_eq(old->uid, keuid) && |
481 | !uid_eq(old->euid, keuid) && | 481 | !uid_eq(old->euid, keuid) && |
482 | !uid_eq(old->suid, keuid) && | 482 | !uid_eq(old->suid, keuid) && |
483 | !nsown_capable(CAP_SETUID)) | 483 | !ns_capable(old->user_ns, CAP_SETUID)) |
484 | goto error; | 484 | goto error; |
485 | } | 485 | } |
486 | 486 | ||
@@ -534,7 +534,7 @@ SYSCALL_DEFINE1(setuid, uid_t, uid) | |||
534 | old = current_cred(); | 534 | old = current_cred(); |
535 | 535 | ||
536 | retval = -EPERM; | 536 | retval = -EPERM; |
537 | if (nsown_capable(CAP_SETUID)) { | 537 | if (ns_capable(old->user_ns, CAP_SETUID)) { |
538 | new->suid = new->uid = kuid; | 538 | new->suid = new->uid = kuid; |
539 | if (!uid_eq(kuid, old->uid)) { | 539 | if (!uid_eq(kuid, old->uid)) { |
540 | retval = set_user(new); | 540 | retval = set_user(new); |
@@ -591,7 +591,7 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) | |||
591 | old = current_cred(); | 591 | old = current_cred(); |
592 | 592 | ||
593 | retval = -EPERM; | 593 | retval = -EPERM; |
594 | if (!nsown_capable(CAP_SETUID)) { | 594 | if (!ns_capable(old->user_ns, CAP_SETUID)) { |
595 | if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) && | 595 | if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) && |
596 | !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid)) | 596 | !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid)) |
597 | goto error; | 597 | goto error; |
@@ -673,7 +673,7 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) | |||
673 | old = current_cred(); | 673 | old = current_cred(); |
674 | 674 | ||
675 | retval = -EPERM; | 675 | retval = -EPERM; |
676 | if (!nsown_capable(CAP_SETGID)) { | 676 | if (!ns_capable(old->user_ns, CAP_SETGID)) { |
677 | if (rgid != (gid_t) -1 && !gid_eq(krgid, old->gid) && | 677 | if (rgid != (gid_t) -1 && !gid_eq(krgid, old->gid) && |
678 | !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid)) | 678 | !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid)) |
679 | goto error; | 679 | goto error; |
@@ -744,7 +744,7 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) | |||
744 | 744 | ||
745 | if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) || | 745 | if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) || |
746 | uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) || | 746 | uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) || |
747 | nsown_capable(CAP_SETUID)) { | 747 | ns_capable(old->user_ns, CAP_SETUID)) { |
748 | if (!uid_eq(kuid, old->fsuid)) { | 748 | if (!uid_eq(kuid, old->fsuid)) { |
749 | new->fsuid = kuid; | 749 | new->fsuid = kuid; |
750 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) | 750 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) |
@@ -783,7 +783,7 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) | |||
783 | 783 | ||
784 | if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->egid) || | 784 | if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->egid) || |
785 | gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) || | 785 | gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) || |
786 | nsown_capable(CAP_SETGID)) { | 786 | ns_capable(old->user_ns, CAP_SETGID)) { |
787 | if (!gid_eq(kgid, old->fsgid)) { | 787 | if (!gid_eq(kgid, old->fsgid)) { |
788 | new->fsgid = kgid; | 788 | new->fsgid = kgid; |
789 | goto change_okay; | 789 | goto change_okay; |
diff --git a/kernel/uid16.c b/kernel/uid16.c index f6c83d7ef000..602e5bbbceff 100644 --- a/kernel/uid16.c +++ b/kernel/uid16.c | |||
@@ -176,7 +176,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist) | |||
176 | struct group_info *group_info; | 176 | struct group_info *group_info; |
177 | int retval; | 177 | int retval; |
178 | 178 | ||
179 | if (!nsown_capable(CAP_SETGID)) | 179 | if (!ns_capable(current_user_ns(), CAP_SETGID)) |
180 | return -EPERM; | 180 | return -EPERM; |
181 | if ((unsigned)gidsetsize > NGROUPS_MAX) | 181 | if ((unsigned)gidsetsize > NGROUPS_MAX) |
182 | return -EINVAL; | 182 | return -EINVAL; |
diff --git a/kernel/user.c b/kernel/user.c index 69b4c3d48cde..5bbb91988e69 100644 --- a/kernel/user.c +++ b/kernel/user.c | |||
@@ -51,8 +51,6 @@ struct user_namespace init_user_ns = { | |||
51 | .owner = GLOBAL_ROOT_UID, | 51 | .owner = GLOBAL_ROOT_UID, |
52 | .group = GLOBAL_ROOT_GID, | 52 | .group = GLOBAL_ROOT_GID, |
53 | .proc_inum = PROC_USER_INIT_INO, | 53 | .proc_inum = PROC_USER_INIT_INO, |
54 | .may_mount_sysfs = true, | ||
55 | .may_mount_proc = true, | ||
56 | }; | 54 | }; |
57 | EXPORT_SYMBOL_GPL(init_user_ns); | 55 | EXPORT_SYMBOL_GPL(init_user_ns); |
58 | 56 | ||
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 9064b919a406..13fb1134ba58 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
@@ -101,8 +101,6 @@ int create_user_ns(struct cred *new) | |||
101 | 101 | ||
102 | set_cred_user_ns(new, ns); | 102 | set_cred_user_ns(new, ns); |
103 | 103 | ||
104 | update_mnt_policy(ns); | ||
105 | |||
106 | return 0; | 104 | return 0; |
107 | } | 105 | } |
108 | 106 | ||
diff --git a/kernel/utsname.c b/kernel/utsname.c index 2fc8576efaa8..fd393124e507 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c | |||
@@ -114,7 +114,7 @@ static int utsns_install(struct nsproxy *nsproxy, void *new) | |||
114 | struct uts_namespace *ns = new; | 114 | struct uts_namespace *ns = new; |
115 | 115 | ||
116 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || | 116 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || |
117 | !nsown_capable(CAP_SYS_ADMIN)) | 117 | !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) |
118 | return -EPERM; | 118 | return -EPERM; |
119 | 119 | ||
120 | get_uts_ns(ns); | 120 | get_uts_ns(ns); |
diff --git a/lib/kobject.c b/lib/kobject.c index 1d46c151a4ae..962175134702 100644 --- a/lib/kobject.c +++ b/lib/kobject.c | |||
@@ -931,6 +931,21 @@ const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj) | |||
931 | return kobj_child_ns_ops(kobj->parent); | 931 | return kobj_child_ns_ops(kobj->parent); |
932 | } | 932 | } |
933 | 933 | ||
934 | bool kobj_ns_current_may_mount(enum kobj_ns_type type) | ||
935 | { | ||
936 | bool may_mount = false; | ||
937 | |||
938 | if (type == KOBJ_NS_TYPE_NONE) | ||
939 | return true; | ||
940 | |||
941 | spin_lock(&kobj_ns_type_lock); | ||
942 | if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && | ||
943 | kobj_ns_ops_tbl[type]) | ||
944 | may_mount = kobj_ns_ops_tbl[type]->current_may_mount(); | ||
945 | spin_unlock(&kobj_ns_type_lock); | ||
946 | |||
947 | return may_mount; | ||
948 | } | ||
934 | 949 | ||
935 | void *kobj_ns_grab_current(enum kobj_ns_type type) | 950 | void *kobj_ns_grab_current(enum kobj_ns_type type) |
936 | { | 951 | { |
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 3f40ea9de814..d954b56b4e47 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c | |||
@@ -1196,6 +1196,13 @@ static void remove_queue_kobjects(struct net_device *net) | |||
1196 | #endif | 1196 | #endif |
1197 | } | 1197 | } |
1198 | 1198 | ||
1199 | static bool net_current_may_mount(void) | ||
1200 | { | ||
1201 | struct net *net = current->nsproxy->net_ns; | ||
1202 | |||
1203 | return ns_capable(net->user_ns, CAP_SYS_ADMIN); | ||
1204 | } | ||
1205 | |||
1199 | static void *net_grab_current_ns(void) | 1206 | static void *net_grab_current_ns(void) |
1200 | { | 1207 | { |
1201 | struct net *ns = current->nsproxy->net_ns; | 1208 | struct net *ns = current->nsproxy->net_ns; |
@@ -1218,6 +1225,7 @@ static const void *net_netlink_ns(struct sock *sk) | |||
1218 | 1225 | ||
1219 | struct kobj_ns_type_operations net_ns_type_operations = { | 1226 | struct kobj_ns_type_operations net_ns_type_operations = { |
1220 | .type = KOBJ_NS_TYPE_NET, | 1227 | .type = KOBJ_NS_TYPE_NET, |
1228 | .current_may_mount = net_current_may_mount, | ||
1221 | .grab_current_ns = net_grab_current_ns, | 1229 | .grab_current_ns = net_grab_current_ns, |
1222 | .netlink_ns = net_netlink_ns, | 1230 | .netlink_ns = net_netlink_ns, |
1223 | .initial_ns = net_initial_ns, | 1231 | .initial_ns = net_initial_ns, |
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index f97652036754..81d3a9a08453 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
@@ -651,7 +651,7 @@ static int netns_install(struct nsproxy *nsproxy, void *ns) | |||
651 | struct net *net = ns; | 651 | struct net *net = ns; |
652 | 652 | ||
653 | if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) || | 653 | if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) || |
654 | !nsown_capable(CAP_SYS_ADMIN)) | 654 | !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) |
655 | return -EPERM; | 655 | return -EPERM; |
656 | 656 | ||
657 | put_net(nsproxy->net_ns); | 657 | put_net(nsproxy->net_ns); |
diff --git a/net/core/scm.c b/net/core/scm.c index b4da80b1cc07..b442e7e25e60 100644 --- a/net/core/scm.c +++ b/net/core/scm.c | |||
@@ -56,9 +56,9 @@ static __inline__ int scm_check_creds(struct ucred *creds) | |||
56 | if ((creds->pid == task_tgid_vnr(current) || | 56 | if ((creds->pid == task_tgid_vnr(current) || |
57 | ns_capable(task_active_pid_ns(current)->user_ns, CAP_SYS_ADMIN)) && | 57 | ns_capable(task_active_pid_ns(current)->user_ns, CAP_SYS_ADMIN)) && |
58 | ((uid_eq(uid, cred->uid) || uid_eq(uid, cred->euid) || | 58 | ((uid_eq(uid, cred->uid) || uid_eq(uid, cred->euid) || |
59 | uid_eq(uid, cred->suid)) || nsown_capable(CAP_SETUID)) && | 59 | uid_eq(uid, cred->suid)) || ns_capable(cred->user_ns, CAP_SETUID)) && |
60 | ((gid_eq(gid, cred->gid) || gid_eq(gid, cred->egid) || | 60 | ((gid_eq(gid, cred->gid) || gid_eq(gid, cred->egid) || |
61 | gid_eq(gid, cred->sgid)) || nsown_capable(CAP_SETGID))) { | 61 | gid_eq(gid, cred->sgid)) || ns_capable(cred->user_ns, CAP_SETGID))) { |
62 | return 0; | 62 | return 0; |
63 | } | 63 | } |
64 | return -EPERM; | 64 | return -EPERM; |
diff --git a/security/commoncap.c b/security/commoncap.c index c44b6fe6648e..b9d613e0ef14 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -768,16 +768,16 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags) | |||
768 | */ | 768 | */ |
769 | static int cap_safe_nice(struct task_struct *p) | 769 | static int cap_safe_nice(struct task_struct *p) |
770 | { | 770 | { |
771 | int is_subset; | 771 | int is_subset, ret = 0; |
772 | 772 | ||
773 | rcu_read_lock(); | 773 | rcu_read_lock(); |
774 | is_subset = cap_issubset(__task_cred(p)->cap_permitted, | 774 | is_subset = cap_issubset(__task_cred(p)->cap_permitted, |
775 | current_cred()->cap_permitted); | 775 | current_cred()->cap_permitted); |
776 | if (!is_subset && !ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) | ||
777 | ret = -EPERM; | ||
776 | rcu_read_unlock(); | 778 | rcu_read_unlock(); |
777 | 779 | ||
778 | if (!is_subset && !capable(CAP_SYS_NICE)) | 780 | return ret; |
779 | return -EPERM; | ||
780 | return 0; | ||
781 | } | 781 | } |
782 | 782 | ||
783 | /** | 783 | /** |
@@ -824,7 +824,7 @@ int cap_task_setnice(struct task_struct *p, int nice) | |||
824 | */ | 824 | */ |
825 | static long cap_prctl_drop(struct cred *new, unsigned long cap) | 825 | static long cap_prctl_drop(struct cred *new, unsigned long cap) |
826 | { | 826 | { |
827 | if (!capable(CAP_SETPCAP)) | 827 | if (!ns_capable(current_user_ns(), CAP_SETPCAP)) |
828 | return -EPERM; | 828 | return -EPERM; |
829 | if (!cap_valid(cap)) | 829 | if (!cap_valid(cap)) |
830 | return -EINVAL; | 830 | return -EINVAL; |