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