diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2012-07-26 09:24:06 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2012-11-20 07:18:13 -0500 |
commit | cde1975bc242f3e1072bde623ef378e547b73f91 (patch) | |
tree | 2c40083144c71d2aa2be39ed65f610570261f647 /kernel/user_namespace.c | |
parent | 4c44aaafa8108f584831850ab48a975e971db2de (diff) |
userns: Implent proc namespace operations
This allows entering a user namespace, and the ability
to store a reference to a user namespace with a bind
mount.
Addition of missing userns_ns_put in userns_install
from Gao feng <gaofeng@cn.fujitsu.com>
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'kernel/user_namespace.c')
-rw-r--r-- | kernel/user_namespace.c | 90 |
1 files changed, 73 insertions, 17 deletions
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 49096d559e08..a9460774e77d 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 |
@@ -53,27 +72,12 @@ int create_user_ns(struct cred *new) | |||
53 | return -ENOMEM; | 72 | return -ENOMEM; |
54 | 73 | ||
55 | kref_init(&ns->kref); | 74 | kref_init(&ns->kref); |
75 | /* Leave the new->user_ns reference with the new user namespace. */ | ||
56 | ns->parent = parent_ns; | 76 | ns->parent = parent_ns; |
57 | ns->owner = owner; | 77 | ns->owner = owner; |
58 | ns->group = group; | 78 | ns->group = group; |
59 | 79 | ||
60 | /* Start with the same capabilities as init but useless for doing | 80 | 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 | 81 | ||
78 | return 0; | 82 | return 0; |
79 | } | 83 | } |
@@ -737,6 +741,58 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid, | |||
737 | return false; | 741 | return false; |
738 | } | 742 | } |
739 | 743 | ||
744 | static void *userns_get(struct task_struct *task) | ||
745 | { | ||
746 | struct user_namespace *user_ns; | ||
747 | |||
748 | rcu_read_lock(); | ||
749 | user_ns = get_user_ns(__task_cred(task)->user_ns); | ||
750 | rcu_read_unlock(); | ||
751 | |||
752 | return user_ns; | ||
753 | } | ||
754 | |||
755 | static void userns_put(void *ns) | ||
756 | { | ||
757 | put_user_ns(ns); | ||
758 | } | ||
759 | |||
760 | static int userns_install(struct nsproxy *nsproxy, void *ns) | ||
761 | { | ||
762 | struct user_namespace *user_ns = ns; | ||
763 | struct cred *cred; | ||
764 | |||
765 | /* Don't allow gaining capabilities by reentering | ||
766 | * the same user namespace. | ||
767 | */ | ||
768 | if (user_ns == current_user_ns()) | ||
769 | return -EINVAL; | ||
770 | |||
771 | /* Threaded many not enter a different user namespace */ | ||
772 | if (atomic_read(¤t->mm->mm_users) > 1) | ||
773 | return -EINVAL; | ||
774 | |||
775 | if (!ns_capable(user_ns, CAP_SYS_ADMIN)) | ||
776 | return -EPERM; | ||
777 | |||
778 | cred = prepare_creds(); | ||
779 | if (!cred) | ||
780 | return -ENOMEM; | ||
781 | |||
782 | put_user_ns(cred->user_ns); | ||
783 | set_cred_user_ns(cred, get_user_ns(user_ns)); | ||
784 | |||
785 | return commit_creds(cred); | ||
786 | } | ||
787 | |||
788 | const struct proc_ns_operations userns_operations = { | ||
789 | .name = "user", | ||
790 | .type = CLONE_NEWUSER, | ||
791 | .get = userns_get, | ||
792 | .put = userns_put, | ||
793 | .install = userns_install, | ||
794 | }; | ||
795 | |||
740 | static __init int user_namespaces_init(void) | 796 | static __init int user_namespaces_init(void) |
741 | { | 797 | { |
742 | user_ns_cachep = KMEM_CACHE(user_namespace, SLAB_PANIC); | 798 | user_ns_cachep = KMEM_CACHE(user_namespace, SLAB_PANIC); |