diff options
| -rw-r--r-- | include/linux/sched.h | 1 | ||||
| -rw-r--r-- | include/linux/user_namespace.h | 4 | ||||
| -rw-r--r-- | kernel/fork.c | 2 | ||||
| -rw-r--r-- | kernel/nsproxy.c | 5 | ||||
| -rw-r--r-- | kernel/user_namespace.c | 46 |
5 files changed, 54 insertions, 4 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index c667255d70db..731edaca8ffd 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #define CLONE_STOPPED 0x02000000 /* Start in stopped state */ | 26 | #define CLONE_STOPPED 0x02000000 /* Start in stopped state */ |
| 27 | #define CLONE_NEWUTS 0x04000000 /* New utsname group? */ | 27 | #define CLONE_NEWUTS 0x04000000 /* New utsname group? */ |
| 28 | #define CLONE_NEWIPC 0x08000000 /* New ipcs */ | 28 | #define CLONE_NEWIPC 0x08000000 /* New ipcs */ |
| 29 | #define CLONE_NEWUSER 0x10000000 /* New user namespace */ | ||
| 29 | 30 | ||
| 30 | /* | 31 | /* |
| 31 | * Scheduling policies | 32 | * Scheduling policies |
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 92a45867ecfb..bb320573bb9e 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include <linux/kref.h> | 4 | #include <linux/kref.h> |
| 5 | #include <linux/nsproxy.h> | 5 | #include <linux/nsproxy.h> |
| 6 | #include <linux/sched.h> | 6 | #include <linux/sched.h> |
| 7 | #include <linux/err.h> | ||
| 7 | 8 | ||
| 8 | #define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 8) | 9 | #define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 8) |
| 9 | #define UIDHASH_SZ (1 << UIDHASH_BITS) | 10 | #define UIDHASH_SZ (1 << UIDHASH_BITS) |
| @@ -45,6 +46,9 @@ static inline struct user_namespace *get_user_ns(struct user_namespace *ns) | |||
| 45 | static inline struct user_namespace *copy_user_ns(int flags, | 46 | static inline struct user_namespace *copy_user_ns(int flags, |
| 46 | struct user_namespace *old_ns) | 47 | struct user_namespace *old_ns) |
| 47 | { | 48 | { |
| 49 | if (flags & CLONE_NEWUSER) | ||
| 50 | return ERR_PTR(-EINVAL); | ||
| 51 | |||
| 48 | return NULL; | 52 | return NULL; |
| 49 | } | 53 | } |
| 50 | 54 | ||
diff --git a/kernel/fork.c b/kernel/fork.c index 13cf0978780a..7c5c5888e00a 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -1606,7 +1606,7 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
| 1606 | err = -EINVAL; | 1606 | err = -EINVAL; |
| 1607 | if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| | 1607 | if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| |
| 1608 | CLONE_VM|CLONE_FILES|CLONE_SYSVSEM| | 1608 | CLONE_VM|CLONE_FILES|CLONE_SYSVSEM| |
| 1609 | CLONE_NEWUTS|CLONE_NEWIPC)) | 1609 | CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWUSER)) |
| 1610 | goto bad_unshare_out; | 1610 | goto bad_unshare_out; |
| 1611 | 1611 | ||
| 1612 | if ((err = unshare_thread(unshare_flags))) | 1612 | if ((err = unshare_thread(unshare_flags))) |
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 895e3a3f2044..5aa28e219487 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c | |||
| @@ -117,7 +117,7 @@ int copy_namespaces(int flags, struct task_struct *tsk) | |||
| 117 | 117 | ||
| 118 | get_nsproxy(old_ns); | 118 | get_nsproxy(old_ns); |
| 119 | 119 | ||
| 120 | if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC))) | 120 | if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER))) |
| 121 | return 0; | 121 | return 0; |
| 122 | 122 | ||
| 123 | if (!capable(CAP_SYS_ADMIN)) { | 123 | if (!capable(CAP_SYS_ADMIN)) { |
| @@ -161,7 +161,8 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags, | |||
| 161 | { | 161 | { |
| 162 | int err = 0; | 162 | int err = 0; |
| 163 | 163 | ||
| 164 | if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC))) | 164 | if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | |
| 165 | CLONE_NEWUSER))) | ||
| 165 | return 0; | 166 | return 0; |
| 166 | 167 | ||
| 167 | if (!capable(CAP_SYS_ADMIN)) | 168 | if (!capable(CAP_SYS_ADMIN)) |
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 3d7964209774..89a27e8b17fb 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
| @@ -21,6 +21,45 @@ EXPORT_SYMBOL_GPL(init_user_ns); | |||
| 21 | 21 | ||
| 22 | #ifdef CONFIG_USER_NS | 22 | #ifdef CONFIG_USER_NS |
| 23 | 23 | ||
| 24 | /* | ||
| 25 | * Clone a new ns copying an original user ns, setting refcount to 1 | ||
| 26 | * @old_ns: namespace to clone | ||
| 27 | * Return NULL on error (failure to kmalloc), new ns otherwise | ||
| 28 | */ | ||
| 29 | static struct user_namespace *clone_user_ns(struct user_namespace *old_ns) | ||
| 30 | { | ||
| 31 | struct user_namespace *ns; | ||
| 32 | struct user_struct *new_user; | ||
| 33 | int n; | ||
| 34 | |||
| 35 | ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL); | ||
| 36 | if (!ns) | ||
| 37 | return NULL; | ||
| 38 | |||
| 39 | kref_init(&ns->kref); | ||
| 40 | |||
| 41 | for (n = 0; n < UIDHASH_SZ; ++n) | ||
| 42 | INIT_LIST_HEAD(ns->uidhash_table + n); | ||
| 43 | |||
| 44 | /* Insert new root user. */ | ||
| 45 | ns->root_user = alloc_uid(ns, 0); | ||
| 46 | if (!ns->root_user) { | ||
| 47 | kfree(ns); | ||
| 48 | return NULL; | ||
| 49 | } | ||
| 50 | |||
| 51 | /* Reset current->user with a new one */ | ||
| 52 | new_user = alloc_uid(ns, current->uid); | ||
| 53 | if (!new_user) { | ||
| 54 | free_uid(ns->root_user); | ||
| 55 | kfree(ns); | ||
| 56 | return NULL; | ||
| 57 | } | ||
| 58 | |||
| 59 | switch_uid(new_user); | ||
| 60 | return ns; | ||
| 61 | } | ||
| 62 | |||
| 24 | struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns) | 63 | struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns) |
| 25 | { | 64 | { |
| 26 | struct user_namespace *new_ns; | 65 | struct user_namespace *new_ns; |
| @@ -28,7 +67,12 @@ struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns) | |||
| 28 | BUG_ON(!old_ns); | 67 | BUG_ON(!old_ns); |
| 29 | get_user_ns(old_ns); | 68 | get_user_ns(old_ns); |
| 30 | 69 | ||
| 31 | new_ns = old_ns; | 70 | if (!(flags & CLONE_NEWUSER)) |
| 71 | return old_ns; | ||
| 72 | |||
| 73 | new_ns = clone_user_ns(old_ns); | ||
| 74 | |||
| 75 | put_user_ns(old_ns); | ||
| 32 | return new_ns; | 76 | return new_ns; |
| 33 | } | 77 | } |
| 34 | 78 | ||
