diff options
Diffstat (limited to 'kernel/user_namespace.c')
| -rw-r--r-- | kernel/user_namespace.c | 147 |
1 files changed, 128 insertions, 19 deletions
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 456a6b9fba34..2b042c42fbc4 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <linux/nsproxy.h> | 9 | #include <linux/nsproxy.h> |
| 10 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
| 11 | #include <linux/user_namespace.h> | 11 | #include <linux/user_namespace.h> |
| 12 | #include <linux/proc_fs.h> | ||
| 12 | #include <linux/highuid.h> | 13 | #include <linux/highuid.h> |
| 13 | #include <linux/cred.h> | 14 | #include <linux/cred.h> |
| 14 | #include <linux/securebits.h> | 15 | #include <linux/securebits.h> |
| @@ -26,6 +27,24 @@ static struct kmem_cache *user_ns_cachep __read_mostly; | |||
| 26 | static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid, | 27 | static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid, |
| 27 | struct uid_gid_map *map); | 28 | struct uid_gid_map *map); |
| 28 | 29 | ||
| 30 | static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns) | ||
| 31 | { | ||
| 32 | /* Start with the same capabilities as init but useless for doing | ||
| 33 | * anything as the capabilities are bound to the new user namespace. | ||
| 34 | */ | ||
| 35 | cred->securebits = SECUREBITS_DEFAULT; | ||
| 36 | cred->cap_inheritable = CAP_EMPTY_SET; | ||
| 37 | cred->cap_permitted = CAP_FULL_SET; | ||
| 38 | cred->cap_effective = CAP_FULL_SET; | ||
| 39 | cred->cap_bset = CAP_FULL_SET; | ||
| 40 | #ifdef CONFIG_KEYS | ||
| 41 | key_put(cred->request_key_auth); | ||
| 42 | cred->request_key_auth = NULL; | ||
| 43 | #endif | ||
| 44 | /* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */ | ||
| 45 | cred->user_ns = user_ns; | ||
| 46 | } | ||
| 47 | |||
| 29 | /* | 48 | /* |
| 30 | * Create a new user namespace, deriving the creator from the user in the | 49 | * Create a new user namespace, deriving the creator from the user in the |
| 31 | * passed credentials, and replacing that user with the new root user for the | 50 | * passed credentials, and replacing that user with the new root user for the |
| @@ -39,6 +58,7 @@ int create_user_ns(struct cred *new) | |||
| 39 | struct user_namespace *ns, *parent_ns = new->user_ns; | 58 | struct user_namespace *ns, *parent_ns = new->user_ns; |
| 40 | kuid_t owner = new->euid; | 59 | kuid_t owner = new->euid; |
| 41 | kgid_t group = new->egid; | 60 | kgid_t group = new->egid; |
| 61 | int ret; | ||
| 42 | 62 | ||
| 43 | /* The creator needs a mapping in the parent user namespace | 63 | /* The creator needs a mapping in the parent user namespace |
| 44 | * or else we won't be able to reasonably tell userspace who | 64 | * or else we won't be able to reasonably tell userspace who |
| @@ -52,38 +72,45 @@ int create_user_ns(struct cred *new) | |||
| 52 | if (!ns) | 72 | if (!ns) |
| 53 | return -ENOMEM; | 73 | return -ENOMEM; |
| 54 | 74 | ||
| 75 | ret = proc_alloc_inum(&ns->proc_inum); | ||
| 76 | if (ret) { | ||
| 77 | kmem_cache_free(user_ns_cachep, ns); | ||
| 78 | return ret; | ||
| 79 | } | ||
| 80 | |||
| 55 | kref_init(&ns->kref); | 81 | kref_init(&ns->kref); |
| 82 | /* Leave the new->user_ns reference with the new user namespace. */ | ||
| 56 | ns->parent = parent_ns; | 83 | ns->parent = parent_ns; |
| 57 | ns->owner = owner; | 84 | ns->owner = owner; |
| 58 | ns->group = group; | 85 | ns->group = group; |
| 59 | 86 | ||
| 60 | /* Start with the same capabilities as init but useless for doing | 87 | set_cred_user_ns(new, ns); |
| 61 | * anything as the capabilities are bound to the new user namespace. | ||
| 62 | */ | ||
| 63 | new->securebits = SECUREBITS_DEFAULT; | ||
| 64 | new->cap_inheritable = CAP_EMPTY_SET; | ||
| 65 | new->cap_permitted = CAP_FULL_SET; | ||
| 66 | new->cap_effective = CAP_FULL_SET; | ||
| 67 | new->cap_bset = CAP_FULL_SET; | ||
| 68 | #ifdef CONFIG_KEYS | ||
| 69 | key_put(new->request_key_auth); | ||
| 70 | new->request_key_auth = NULL; | ||
| 71 | #endif | ||
| 72 | /* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */ | ||
| 73 | |||
| 74 | /* Leave the new->user_ns reference with the new user namespace. */ | ||
| 75 | /* Leave the reference to our user_ns with the new cred. */ | ||
| 76 | new->user_ns = ns; | ||
| 77 | 88 | ||
| 78 | return 0; | 89 | return 0; |
| 79 | } | 90 | } |
| 80 | 91 | ||
| 92 | int unshare_userns(unsigned long unshare_flags, struct cred **new_cred) | ||
| 93 | { | ||
| 94 | struct cred *cred; | ||
| 95 | |||
| 96 | if (!(unshare_flags & CLONE_NEWUSER)) | ||
| 97 | return 0; | ||
| 98 | |||
| 99 | cred = prepare_creds(); | ||
| 100 | if (!cred) | ||
| 101 | return -ENOMEM; | ||
| 102 | |||
| 103 | *new_cred = cred; | ||
| 104 | return create_user_ns(cred); | ||
| 105 | } | ||
| 106 | |||
| 81 | void free_user_ns(struct kref *kref) | 107 | void free_user_ns(struct kref *kref) |
| 82 | { | 108 | { |
| 83 | struct user_namespace *parent, *ns = | 109 | struct user_namespace *parent, *ns = |
| 84 | container_of(kref, struct user_namespace, kref); | 110 | container_of(kref, struct user_namespace, kref); |
| 85 | 111 | ||
| 86 | parent = ns->parent; | 112 | parent = ns->parent; |
| 113 | proc_free_inum(ns->proc_inum); | ||
| 87 | kmem_cache_free(user_ns_cachep, ns); | 114 | kmem_cache_free(user_ns_cachep, ns); |
| 88 | put_user_ns(parent); | 115 | put_user_ns(parent); |
| 89 | } | 116 | } |
| @@ -372,7 +399,7 @@ static int uid_m_show(struct seq_file *seq, void *v) | |||
| 372 | struct user_namespace *lower_ns; | 399 | struct user_namespace *lower_ns; |
| 373 | uid_t lower; | 400 | uid_t lower; |
| 374 | 401 | ||
| 375 | lower_ns = current_user_ns(); | 402 | lower_ns = seq_user_ns(seq); |
| 376 | if ((lower_ns == ns) && lower_ns->parent) | 403 | if ((lower_ns == ns) && lower_ns->parent) |
| 377 | lower_ns = lower_ns->parent; | 404 | lower_ns = lower_ns->parent; |
| 378 | 405 | ||
| @@ -393,7 +420,7 @@ static int gid_m_show(struct seq_file *seq, void *v) | |||
| 393 | struct user_namespace *lower_ns; | 420 | struct user_namespace *lower_ns; |
| 394 | gid_t lower; | 421 | gid_t lower; |
| 395 | 422 | ||
| 396 | lower_ns = current_user_ns(); | 423 | lower_ns = seq_user_ns(seq); |
| 397 | if ((lower_ns == ns) && lower_ns->parent) | 424 | if ((lower_ns == ns) && lower_ns->parent) |
| 398 | lower_ns = lower_ns->parent; | 425 | lower_ns = lower_ns->parent; |
| 399 | 426 | ||
| @@ -669,10 +696,14 @@ ssize_t proc_uid_map_write(struct file *file, const char __user *buf, size_t siz | |||
| 669 | { | 696 | { |
| 670 | struct seq_file *seq = file->private_data; | 697 | struct seq_file *seq = file->private_data; |
| 671 | struct user_namespace *ns = seq->private; | 698 | struct user_namespace *ns = seq->private; |
| 699 | struct user_namespace *seq_ns = seq_user_ns(seq); | ||
| 672 | 700 | ||
| 673 | if (!ns->parent) | 701 | if (!ns->parent) |
| 674 | return -EPERM; | 702 | return -EPERM; |
| 675 | 703 | ||
| 704 | if ((seq_ns != ns) && (seq_ns != ns->parent)) | ||
| 705 | return -EPERM; | ||
| 706 | |||
| 676 | return map_write(file, buf, size, ppos, CAP_SETUID, | 707 | return map_write(file, buf, size, ppos, CAP_SETUID, |
| 677 | &ns->uid_map, &ns->parent->uid_map); | 708 | &ns->uid_map, &ns->parent->uid_map); |
| 678 | } | 709 | } |
| @@ -681,10 +712,14 @@ ssize_t proc_gid_map_write(struct file *file, const char __user *buf, size_t siz | |||
| 681 | { | 712 | { |
| 682 | struct seq_file *seq = file->private_data; | 713 | struct seq_file *seq = file->private_data; |
| 683 | struct user_namespace *ns = seq->private; | 714 | struct user_namespace *ns = seq->private; |
| 715 | struct user_namespace *seq_ns = seq_user_ns(seq); | ||
| 684 | 716 | ||
| 685 | if (!ns->parent) | 717 | if (!ns->parent) |
| 686 | return -EPERM; | 718 | return -EPERM; |
| 687 | 719 | ||
| 720 | if ((seq_ns != ns) && (seq_ns != ns->parent)) | ||
| 721 | return -EPERM; | ||
| 722 | |||
| 688 | return map_write(file, buf, size, ppos, CAP_SETGID, | 723 | return map_write(file, buf, size, ppos, CAP_SETGID, |
| 689 | &ns->gid_map, &ns->parent->gid_map); | 724 | &ns->gid_map, &ns->parent->gid_map); |
| 690 | } | 725 | } |
| @@ -709,6 +744,21 @@ ssize_t proc_projid_map_write(struct file *file, const char __user *buf, size_t | |||
| 709 | static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid, | 744 | static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid, |
| 710 | struct uid_gid_map *new_map) | 745 | struct uid_gid_map *new_map) |
| 711 | { | 746 | { |
| 747 | /* Allow mapping to your own filesystem ids */ | ||
| 748 | if ((new_map->nr_extents == 1) && (new_map->extent[0].count == 1)) { | ||
| 749 | u32 id = new_map->extent[0].lower_first; | ||
| 750 | if (cap_setid == CAP_SETUID) { | ||
| 751 | kuid_t uid = make_kuid(ns->parent, id); | ||
| 752 | if (uid_eq(uid, current_fsuid())) | ||
| 753 | return true; | ||
| 754 | } | ||
| 755 | else if (cap_setid == CAP_SETGID) { | ||
| 756 | kgid_t gid = make_kgid(ns->parent, id); | ||
| 757 | if (gid_eq(gid, current_fsgid())) | ||
| 758 | return true; | ||
| 759 | } | ||
| 760 | } | ||
| 761 | |||
| 712 | /* Allow anyone to set a mapping that doesn't require privilege */ | 762 | /* Allow anyone to set a mapping that doesn't require privilege */ |
| 713 | if (!cap_valid(cap_setid)) | 763 | if (!cap_valid(cap_setid)) |
| 714 | return true; | 764 | return true; |
| @@ -722,6 +772,65 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid, | |||
| 722 | return false; | 772 | return false; |
| 723 | } | 773 | } |
| 724 | 774 | ||
| 775 | static void *userns_get(struct task_struct *task) | ||
| 776 | { | ||
| 777 | struct user_namespace *user_ns; | ||
| 778 | |||
| 779 | rcu_read_lock(); | ||
| 780 | user_ns = get_user_ns(__task_cred(task)->user_ns); | ||
| 781 | rcu_read_unlock(); | ||
| 782 | |||
| 783 | return user_ns; | ||
| 784 | } | ||
| 785 | |||
| 786 | static void userns_put(void *ns) | ||
| 787 | { | ||
| 788 | put_user_ns(ns); | ||
| 789 | } | ||
| 790 | |||
| 791 | static int userns_install(struct nsproxy *nsproxy, void *ns) | ||
| 792 | { | ||
| 793 | struct user_namespace *user_ns = ns; | ||
| 794 | struct cred *cred; | ||
| 795 | |||
| 796 | /* Don't allow gaining capabilities by reentering | ||
| 797 | * the same user namespace. | ||
| 798 | */ | ||
| 799 | if (user_ns == current_user_ns()) | ||
| 800 | return -EINVAL; | ||
| 801 | |||
| 802 | /* Threaded processes may not enter a different user namespace */ | ||
| 803 | if (atomic_read(¤t->mm->mm_users) > 1) | ||
| 804 | return -EINVAL; | ||
| 805 | |||
| 806 | if (!ns_capable(user_ns, CAP_SYS_ADMIN)) | ||
| 807 | return -EPERM; | ||
| 808 | |||
| 809 | cred = prepare_creds(); | ||
| 810 | if (!cred) | ||
| 811 | return -ENOMEM; | ||
| 812 | |||
| 813 | put_user_ns(cred->user_ns); | ||
| 814 | set_cred_user_ns(cred, get_user_ns(user_ns)); | ||
| 815 | |||
| 816 | return commit_creds(cred); | ||
| 817 | } | ||
| 818 | |||
| 819 | static unsigned int userns_inum(void *ns) | ||
| 820 | { | ||
| 821 | struct user_namespace *user_ns = ns; | ||
| 822 | return user_ns->proc_inum; | ||
| 823 | } | ||
| 824 | |||
| 825 | const struct proc_ns_operations userns_operations = { | ||
| 826 | .name = "user", | ||
| 827 | .type = CLONE_NEWUSER, | ||
| 828 | .get = userns_get, | ||
| 829 | .put = userns_put, | ||
| 830 | .install = userns_install, | ||
| 831 | .inum = userns_inum, | ||
| 832 | }; | ||
| 833 | |||
| 725 | static __init int user_namespaces_init(void) | 834 | static __init int user_namespaces_init(void) |
| 726 | { | 835 | { |
| 727 | user_ns_cachep = KMEM_CACHE(user_namespace, SLAB_PANIC); | 836 | user_ns_cachep = KMEM_CACHE(user_namespace, SLAB_PANIC); |
