aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/proc/namespaces.c4
-rw-r--r--include/linux/proc_fs.h1
-rw-r--r--kernel/user_namespace.c90
3 files changed, 78 insertions, 17 deletions
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index 2a17fd9ae6a9..030250c27d70 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -11,6 +11,7 @@
11#include <net/net_namespace.h> 11#include <net/net_namespace.h>
12#include <linux/ipc_namespace.h> 12#include <linux/ipc_namespace.h>
13#include <linux/pid_namespace.h> 13#include <linux/pid_namespace.h>
14#include <linux/user_namespace.h>
14#include "internal.h" 15#include "internal.h"
15 16
16 17
@@ -27,6 +28,9 @@ static const struct proc_ns_operations *ns_entries[] = {
27#ifdef CONFIG_PID_NS 28#ifdef CONFIG_PID_NS
28 &pidns_operations, 29 &pidns_operations,
29#endif 30#endif
31#ifdef CONFIG_USER_NS
32 &userns_operations,
33#endif
30 &mntns_operations, 34 &mntns_operations,
31}; 35};
32 36
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 9014c041e752..31447819bc55 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -258,6 +258,7 @@ extern const struct proc_ns_operations netns_operations;
258extern const struct proc_ns_operations utsns_operations; 258extern const struct proc_ns_operations utsns_operations;
259extern const struct proc_ns_operations ipcns_operations; 259extern const struct proc_ns_operations ipcns_operations;
260extern const struct proc_ns_operations pidns_operations; 260extern const struct proc_ns_operations pidns_operations;
261extern const struct proc_ns_operations userns_operations;
261extern const struct proc_ns_operations mntns_operations; 262extern const struct proc_ns_operations mntns_operations;
262 263
263union proc_op { 264union proc_op {
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;
26static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid, 27static 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
30static 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
744static 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
755static void userns_put(void *ns)
756{
757 put_user_ns(ns);
758}
759
760static 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(&current->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
788const 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
740static __init int user_namespaces_init(void) 796static __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);