diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2016-08-08 15:25:30 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2016-08-08 15:42:03 -0400 |
commit | d08311dd6fd8444e39710dd2fb97562895aed8fa (patch) | |
tree | cc695dce4603db22fe5bb0789467ae4d9481f084 | |
parent | aba356616386e6e573a34c6d64ed12443686e5c8 (diff) |
cgroupns: Add a limit on the number of cgroup namespaces
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
-rw-r--r-- | include/linux/cgroup.h | 1 | ||||
-rw-r--r-- | include/linux/user_namespace.h | 1 | ||||
-rw-r--r-- | kernel/cgroup.c | 18 | ||||
-rw-r--r-- | kernel/ucount.c | 1 |
4 files changed, 21 insertions, 0 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 984f73b719a9..1ed92812785a 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
@@ -621,6 +621,7 @@ struct cgroup_namespace { | |||
621 | atomic_t count; | 621 | atomic_t count; |
622 | struct ns_common ns; | 622 | struct ns_common ns; |
623 | struct user_namespace *user_ns; | 623 | struct user_namespace *user_ns; |
624 | struct ucounts *ucounts; | ||
624 | struct css_set *root_cset; | 625 | struct css_set *root_cset; |
625 | }; | 626 | }; |
626 | 627 | ||
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index e1d672186f00..d067f0d3038e 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h | |||
@@ -29,6 +29,7 @@ enum ucount_type { | |||
29 | UCOUNT_PID_NAMESPACES, | 29 | UCOUNT_PID_NAMESPACES, |
30 | UCOUNT_UTS_NAMESPACES, | 30 | UCOUNT_UTS_NAMESPACES, |
31 | UCOUNT_IPC_NAMESPACES, | 31 | UCOUNT_IPC_NAMESPACES, |
32 | UCOUNT_CGROUP_NAMESPACES, | ||
32 | UCOUNT_COUNTS, | 33 | UCOUNT_COUNTS, |
33 | }; | 34 | }; |
34 | 35 | ||
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index d1c51b7f5221..e9e4427fec46 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -6295,6 +6295,16 @@ void cgroup_sk_free(struct sock_cgroup_data *skcd) | |||
6295 | 6295 | ||
6296 | /* cgroup namespaces */ | 6296 | /* cgroup namespaces */ |
6297 | 6297 | ||
6298 | static struct ucounts *inc_cgroup_namespaces(struct user_namespace *ns) | ||
6299 | { | ||
6300 | return inc_ucount(ns, current_euid(), UCOUNT_CGROUP_NAMESPACES); | ||
6301 | } | ||
6302 | |||
6303 | static void dec_cgroup_namespaces(struct ucounts *ucounts) | ||
6304 | { | ||
6305 | dec_ucount(ucounts, UCOUNT_CGROUP_NAMESPACES); | ||
6306 | } | ||
6307 | |||
6298 | static struct cgroup_namespace *alloc_cgroup_ns(void) | 6308 | static struct cgroup_namespace *alloc_cgroup_ns(void) |
6299 | { | 6309 | { |
6300 | struct cgroup_namespace *new_ns; | 6310 | struct cgroup_namespace *new_ns; |
@@ -6316,6 +6326,7 @@ static struct cgroup_namespace *alloc_cgroup_ns(void) | |||
6316 | void free_cgroup_ns(struct cgroup_namespace *ns) | 6326 | void free_cgroup_ns(struct cgroup_namespace *ns) |
6317 | { | 6327 | { |
6318 | put_css_set(ns->root_cset); | 6328 | put_css_set(ns->root_cset); |
6329 | dec_cgroup_namespaces(ns->ucounts); | ||
6319 | put_user_ns(ns->user_ns); | 6330 | put_user_ns(ns->user_ns); |
6320 | ns_free_inum(&ns->ns); | 6331 | ns_free_inum(&ns->ns); |
6321 | kfree(ns); | 6332 | kfree(ns); |
@@ -6327,6 +6338,7 @@ struct cgroup_namespace *copy_cgroup_ns(unsigned long flags, | |||
6327 | struct cgroup_namespace *old_ns) | 6338 | struct cgroup_namespace *old_ns) |
6328 | { | 6339 | { |
6329 | struct cgroup_namespace *new_ns; | 6340 | struct cgroup_namespace *new_ns; |
6341 | struct ucounts *ucounts; | ||
6330 | struct css_set *cset; | 6342 | struct css_set *cset; |
6331 | 6343 | ||
6332 | BUG_ON(!old_ns); | 6344 | BUG_ON(!old_ns); |
@@ -6340,6 +6352,10 @@ struct cgroup_namespace *copy_cgroup_ns(unsigned long flags, | |||
6340 | if (!ns_capable(user_ns, CAP_SYS_ADMIN)) | 6352 | if (!ns_capable(user_ns, CAP_SYS_ADMIN)) |
6341 | return ERR_PTR(-EPERM); | 6353 | return ERR_PTR(-EPERM); |
6342 | 6354 | ||
6355 | ucounts = inc_cgroup_namespaces(user_ns); | ||
6356 | if (!ucounts) | ||
6357 | return ERR_PTR(-ENFILE); | ||
6358 | |||
6343 | /* It is not safe to take cgroup_mutex here */ | 6359 | /* It is not safe to take cgroup_mutex here */ |
6344 | spin_lock_irq(&css_set_lock); | 6360 | spin_lock_irq(&css_set_lock); |
6345 | cset = task_css_set(current); | 6361 | cset = task_css_set(current); |
@@ -6349,10 +6365,12 @@ struct cgroup_namespace *copy_cgroup_ns(unsigned long flags, | |||
6349 | new_ns = alloc_cgroup_ns(); | 6365 | new_ns = alloc_cgroup_ns(); |
6350 | if (IS_ERR(new_ns)) { | 6366 | if (IS_ERR(new_ns)) { |
6351 | put_css_set(cset); | 6367 | put_css_set(cset); |
6368 | dec_cgroup_namespaces(ucounts); | ||
6352 | return new_ns; | 6369 | return new_ns; |
6353 | } | 6370 | } |
6354 | 6371 | ||
6355 | new_ns->user_ns = get_user_ns(user_ns); | 6372 | new_ns->user_ns = get_user_ns(user_ns); |
6373 | new_ns->ucounts = ucounts; | ||
6356 | new_ns->root_cset = cset; | 6374 | new_ns->root_cset = cset; |
6357 | 6375 | ||
6358 | return new_ns; | 6376 | return new_ns; |
diff --git a/kernel/ucount.c b/kernel/ucount.c index fbab75424da6..335cc5d2cdd7 100644 --- a/kernel/ucount.c +++ b/kernel/ucount.c | |||
@@ -71,6 +71,7 @@ static struct ctl_table user_table[] = { | |||
71 | UCOUNT_ENTRY("max_pid_namespaces"), | 71 | UCOUNT_ENTRY("max_pid_namespaces"), |
72 | UCOUNT_ENTRY("max_uts_namespaces"), | 72 | UCOUNT_ENTRY("max_uts_namespaces"), |
73 | UCOUNT_ENTRY("max_ipc_namespaces"), | 73 | UCOUNT_ENTRY("max_ipc_namespaces"), |
74 | UCOUNT_ENTRY("max_cgroup_namespaces"), | ||
74 | { } | 75 | { } |
75 | }; | 76 | }; |
76 | #endif /* CONFIG_SYSCTL */ | 77 | #endif /* CONFIG_SYSCTL */ |