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); |