Pull namespace changes from Eric Biederman: "This is an assorted mishmash of small cleanups, enhancements and bug fixes. The major theme is user namespace mount restrictions. nsown_capable is killed as it encourages not thinking about details that need to be considered. A very hard to hit pid namespace exiting bug was finally tracked and fixed. A couple of cleanups to the basic namespace infrastructure. Finally there is an enhancement that makes per user namespace capabilities usable as capabilities, and an enhancement that allows the per userns root to nice other processes in the user namespace" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: userns: Kill nsown_capable it makes the wrong thing easy capabilities: allow nice if we are privileged pidns: Don't have unshare(CLONE_NEWPID) imply CLONE_THREAD userns: Allow PR_CAPBSET_DROP in a user namespace. namespaces: Simplify copy_namespaces so it is clear what is going on. pidns: Fix hang in zap_pid_ns_processes by sending a potentially extra wakeup sysfs: Restrict mounting sysfs userns: Better restrictions on when proc and sysfs can be mounted vfs: Don't copy mount bind mounts of /proc/<pid>/ns/mnt between namespaces kernel/nsproxy.c: Improving a snippet of code. proc: Restrict mounting the proc filesystem vfs: Lock in place mounts from more privileged users
Unified · Split
| @@ -831,6 +831,10 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, · 830 unmodified lines | |||
| 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) · 490 unmodified lines | |||
| 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) · 16 unmodified lines | |||
| 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) · 2 unmodified lines | |||
| 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, · 2 unmodified lines | |||
| 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, · 3 unmodified lines | |||
| 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) · 299 unmodified lines | |||
| 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, · 11 unmodified lines | |||
| 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, · 11 unmodified lines | |||
| 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, · 2 unmodified lines | |||
| 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) · 106 unmodified lines | |||
| 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, · 530 unmodified lines | |||
| 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, · 28 unmodified lines | |||
| 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, · 200 unmodified lines | |||
| 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, · 17 unmodified lines | |||
| 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) · 152 unmodified lines | |||
| 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) · 24 unmodified lines | |||
| 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: · 442 unmodified lines | |||
| 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) |
| @@ -19,11 +19,14 @@ · 18 unmodified lines | |||
| 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 | { |
| @@ -110,7 +110,11 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, · 109 unmodified lines | |||
| 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 | ||
| @@ -112,8 +112,15 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, · 111 unmodified lines | |||
| 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) |
| @@ -210,7 +210,6 @@ extern bool has_ns_capability_noaudit(struct task_struct *t, · 209 unmodified lines | |||
| 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 | ||
| @@ -1900,6 +1900,7 @@ extern int vfs_ustat(dev_t, struct kstatfs *); · 1899 unmodified lines | |||
| 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 | ||
| @@ -39,6 +39,7 @@ enum kobj_ns_type { · 38 unmodified lines | |||
| 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); · 5 unmodified lines | |||
| 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); |
| @@ -48,6 +48,7 @@ struct mnt_namespace; · 47 unmodified lines | |||
| 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 */ |
| @@ -27,8 +27,6 @@ struct user_namespace { · 26 unmodified lines | |||
| 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) · 50 unmodified lines | |||
| 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 */ |
| @@ -171,7 +171,7 @@ static int ipcns_install(struct nsproxy *nsproxy, void *new) · 170 unmodified lines | |||
| 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 */ |
| @@ -432,18 +432,6 @@ bool capable(int cap) · 431 unmodified lines | |||
| 432 | } | 432 | } |
| 433 | EXPORT_SYMBOL(capable); | 433 | EXPORT_SYMBOL(capable); |
| 434 | 434 | ||
| 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 | /** | 435 | /** |
| 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 |
| @@ -1824,11 +1824,6 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) · 1823 unmodified lines | |||
| 1824 | */ | 1824 | */ |
| 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 | /* | ||
| 1828 | * If unsharing a pid namespace must also unshare the thread. | ||
| 1829 | */ | ||
| 1830 | if (unshare_flags & CLONE_NEWPID) | ||
| 1831 | unshare_flags |= CLONE_THREAD; | ||
| 1832 | /* | 1827 | /* |
| 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 | */ |
| @@ -233,7 +233,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) · 232 unmodified lines | |||
| 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; |
| @@ -126,22 +126,16 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) · 125 unmodified lines | |||
| 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) · 1 unmodified line | |||
| 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) |
| @@ -265,6 +265,7 @@ void free_pid(struct pid *pid) · 264 unmodified lines | |||
| 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 |
| @@ -329,7 +329,7 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns) · 328 unmodified lines | |||
| 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 | /* |
| @@ -337,7 +337,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) · 336 unmodified lines | |||
| 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) · 2 unmodified lines | |||
| 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) · 34 unmodified lines | |||
| 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) · 77 unmodified lines | |||
| 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) · 2 unmodified lines | |||
| 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) · 47 unmodified lines | |||
| 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) · 50 unmodified lines | |||
| 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) · 75 unmodified lines | |||
| 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) · 64 unmodified lines | |||
| 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) · 32 unmodified lines | |||
| 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; |
| @@ -176,7 +176,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist) · 175 unmodified lines | |||
| 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; |
| @@ -51,8 +51,6 @@ struct user_namespace init_user_ns = { · 50 unmodified lines | |||
| 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 | ||
| @@ -101,8 +101,6 @@ int create_user_ns(struct cred *new) · 100 unmodified lines | |||
| 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 | ||
| @@ -114,7 +114,7 @@ static int utsns_install(struct nsproxy *nsproxy, void *new) · 113 unmodified lines | |||
| 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); |
| @@ -931,6 +931,21 @@ const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj) · 930 unmodified lines | |||
| 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 | { |
| @@ -1196,6 +1196,13 @@ static void remove_queue_kobjects(struct net_device *net) · 1195 unmodified lines | |||
| 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) · 16 unmodified lines | |||
| 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, |
| @@ -651,7 +651,7 @@ static int netns_install(struct nsproxy *nsproxy, void *ns) · 650 unmodified lines | |||
| 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); |
| @@ -56,9 +56,9 @@ static __inline__ int scm_check_creds(struct ucred *creds) · 55 unmodified lines | |||
| 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; |
| @@ -768,16 +768,16 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags) · 767 unmodified lines | |||
| 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) · 40 unmodified lines | |||
| 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; |