aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/nsproxy.c9
-rw-r--r--kernel/sys.c5
-rw-r--r--kernel/user.c18
-rw-r--r--kernel/user_namespace.c43
6 files changed, 66 insertions, 13 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index fa8efd437afb..2a999836ca18 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -4,7 +4,7 @@
4 4
5obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ 5obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
6 exit.o itimer.o time.o softirq.o resource.o \ 6 exit.o itimer.o time.o softirq.o resource.o \
7 sysctl.o capability.o ptrace.o timer.o user.o \ 7 sysctl.o capability.o ptrace.o timer.o user.o user_namespace.o \
8 signal.o sys.o kmod.o workqueue.o pid.o \ 8 signal.o sys.o kmod.o workqueue.o pid.o \
9 rcupdate.o extable.o params.o posix-timers.o \ 9 rcupdate.o extable.o params.o posix-timers.o \
10 kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ 10 kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
diff --git a/kernel/fork.c b/kernel/fork.c
index 4015912aaac2..13cf0978780a 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1002,7 +1002,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1002 if (atomic_read(&p->user->processes) >= 1002 if (atomic_read(&p->user->processes) >=
1003 p->signal->rlim[RLIMIT_NPROC].rlim_cur) { 1003 p->signal->rlim[RLIMIT_NPROC].rlim_cur) {
1004 if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) && 1004 if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&
1005 p->user != &root_user) 1005 p->user != current->nsproxy->user_ns->root_user)
1006 goto bad_fork_free; 1006 goto bad_fork_free;
1007 } 1007 }
1008 1008
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index e38bed75367d..895e3a3f2044 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -79,8 +79,15 @@ static struct nsproxy *create_new_namespaces(int flags, struct task_struct *tsk,
79 if (IS_ERR(new_nsp->pid_ns)) 79 if (IS_ERR(new_nsp->pid_ns))
80 goto out_pid; 80 goto out_pid;
81 81
82 new_nsp->user_ns = copy_user_ns(flags, tsk->nsproxy->user_ns);
83 if (IS_ERR(new_nsp->user_ns))
84 goto out_user;
85
82 return new_nsp; 86 return new_nsp;
83 87
88out_user:
89 if (new_nsp->pid_ns)
90 put_pid_ns(new_nsp->pid_ns);
84out_pid: 91out_pid:
85 if (new_nsp->ipc_ns) 92 if (new_nsp->ipc_ns)
86 put_ipc_ns(new_nsp->ipc_ns); 93 put_ipc_ns(new_nsp->ipc_ns);
@@ -140,6 +147,8 @@ void free_nsproxy(struct nsproxy *ns)
140 put_ipc_ns(ns->ipc_ns); 147 put_ipc_ns(ns->ipc_ns);
141 if (ns->pid_ns) 148 if (ns->pid_ns)
142 put_pid_ns(ns->pid_ns); 149 put_pid_ns(ns->pid_ns);
150 if (ns->user_ns)
151 put_user_ns(ns->user_ns);
143 kfree(ns); 152 kfree(ns);
144} 153}
145 154
diff --git a/kernel/sys.c b/kernel/sys.c
index 872271ccc384..ed92e2f03342 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -35,6 +35,7 @@
35#include <linux/compat.h> 35#include <linux/compat.h>
36#include <linux/syscalls.h> 36#include <linux/syscalls.h>
37#include <linux/kprobes.h> 37#include <linux/kprobes.h>
38#include <linux/user_namespace.h>
38 39
39#include <asm/uaccess.h> 40#include <asm/uaccess.h>
40#include <asm/io.h> 41#include <asm/io.h>
@@ -1078,13 +1079,13 @@ static int set_user(uid_t new_ruid, int dumpclear)
1078{ 1079{
1079 struct user_struct *new_user; 1080 struct user_struct *new_user;
1080 1081
1081 new_user = alloc_uid(new_ruid); 1082 new_user = alloc_uid(current->nsproxy->user_ns, new_ruid);
1082 if (!new_user) 1083 if (!new_user)
1083 return -EAGAIN; 1084 return -EAGAIN;
1084 1085
1085 if (atomic_read(&new_user->processes) >= 1086 if (atomic_read(&new_user->processes) >=
1086 current->signal->rlim[RLIMIT_NPROC].rlim_cur && 1087 current->signal->rlim[RLIMIT_NPROC].rlim_cur &&
1087 new_user != &root_user) { 1088 new_user != current->nsproxy->user_ns->root_user) {
1088 free_uid(new_user); 1089 free_uid(new_user);
1089 return -EAGAIN; 1090 return -EAGAIN;
1090 } 1091 }
diff --git a/kernel/user.c b/kernel/user.c
index 4869563080e9..98b82507797a 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -14,20 +14,19 @@
14#include <linux/bitops.h> 14#include <linux/bitops.h>
15#include <linux/key.h> 15#include <linux/key.h>
16#include <linux/interrupt.h> 16#include <linux/interrupt.h>
17#include <linux/module.h>
18#include <linux/user_namespace.h>
17 19
18/* 20/*
19 * UID task count cache, to get fast user lookup in "alloc_uid" 21 * UID task count cache, to get fast user lookup in "alloc_uid"
20 * when changing user ID's (ie setuid() and friends). 22 * when changing user ID's (ie setuid() and friends).
21 */ 23 */
22 24
23#define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 8)
24#define UIDHASH_SZ (1 << UIDHASH_BITS)
25#define UIDHASH_MASK (UIDHASH_SZ - 1) 25#define UIDHASH_MASK (UIDHASH_SZ - 1)
26#define __uidhashfn(uid) (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK) 26#define __uidhashfn(uid) (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK)
27#define uidhashentry(uid) (uidhash_table + __uidhashfn((uid))) 27#define uidhashentry(ns, uid) ((ns)->uidhash_table + __uidhashfn((uid)))
28 28
29static struct kmem_cache *uid_cachep; 29static struct kmem_cache *uid_cachep;
30static struct list_head uidhash_table[UIDHASH_SZ];
31 30
32/* 31/*
33 * The uidhash_lock is mostly taken from process context, but it is 32 * The uidhash_lock is mostly taken from process context, but it is
@@ -94,9 +93,10 @@ struct user_struct *find_user(uid_t uid)
94{ 93{
95 struct user_struct *ret; 94 struct user_struct *ret;
96 unsigned long flags; 95 unsigned long flags;
96 struct user_namespace *ns = current->nsproxy->user_ns;
97 97
98 spin_lock_irqsave(&uidhash_lock, flags); 98 spin_lock_irqsave(&uidhash_lock, flags);
99 ret = uid_hash_find(uid, uidhashentry(uid)); 99 ret = uid_hash_find(uid, uidhashentry(ns, uid));
100 spin_unlock_irqrestore(&uidhash_lock, flags); 100 spin_unlock_irqrestore(&uidhash_lock, flags);
101 return ret; 101 return ret;
102} 102}
@@ -120,9 +120,9 @@ void free_uid(struct user_struct *up)
120 } 120 }
121} 121}
122 122
123struct user_struct * alloc_uid(uid_t uid) 123struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
124{ 124{
125 struct list_head *hashent = uidhashentry(uid); 125 struct list_head *hashent = uidhashentry(ns, uid);
126 struct user_struct *up; 126 struct user_struct *up;
127 127
128 spin_lock_irq(&uidhash_lock); 128 spin_lock_irq(&uidhash_lock);
@@ -211,11 +211,11 @@ static int __init uid_cache_init(void)
211 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); 211 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
212 212
213 for(n = 0; n < UIDHASH_SZ; ++n) 213 for(n = 0; n < UIDHASH_SZ; ++n)
214 INIT_LIST_HEAD(uidhash_table + n); 214 INIT_LIST_HEAD(init_user_ns.uidhash_table + n);
215 215
216 /* Insert the root user immediately (init already runs as root) */ 216 /* Insert the root user immediately (init already runs as root) */
217 spin_lock_irq(&uidhash_lock); 217 spin_lock_irq(&uidhash_lock);
218 uid_hash_insert(&root_user, uidhashentry(0)); 218 uid_hash_insert(&root_user, uidhashentry(&init_user_ns, 0));
219 spin_unlock_irq(&uidhash_lock); 219 spin_unlock_irq(&uidhash_lock);
220 220
221 return 0; 221 return 0;
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
new file mode 100644
index 000000000000..3d7964209774
--- /dev/null
+++ b/kernel/user_namespace.c
@@ -0,0 +1,43 @@
1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation, version 2 of the
5 * License.
6 */
7
8#include <linux/module.h>
9#include <linux/version.h>
10#include <linux/nsproxy.h>
11#include <linux/user_namespace.h>
12
13struct user_namespace init_user_ns = {
14 .kref = {
15 .refcount = ATOMIC_INIT(2),
16 },
17 .root_user = &root_user,
18};
19
20EXPORT_SYMBOL_GPL(init_user_ns);
21
22#ifdef CONFIG_USER_NS
23
24struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns)
25{
26 struct user_namespace *new_ns;
27
28 BUG_ON(!old_ns);
29 get_user_ns(old_ns);
30
31 new_ns = old_ns;
32 return new_ns;
33}
34
35void free_user_ns(struct kref *kref)
36{
37 struct user_namespace *ns;
38
39 ns = container_of(kref, struct user_namespace, kref);
40 kfree(ns);
41}
42
43#endif /* CONFIG_USER_NS */