diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2016-08-08 15:11:25 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2016-08-08 15:42:02 -0400 |
commit | f7af3d1c03136275b876f58644599b120cf4ffdd (patch) | |
tree | ca152c99d9a25b1bad1ddf1b1ea4026e8da6e7cb | |
parent | f333c700c6100b53050980986be922bb21466e29 (diff) |
utsns: Add a limit on the number of uts namespaces
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
-rw-r--r-- | include/linux/user_namespace.h | 1 | ||||
-rw-r--r-- | include/linux/utsname.h | 1 | ||||
-rw-r--r-- | kernel/ucount.c | 1 | ||||
-rw-r--r-- | kernel/utsname.c | 34 |
4 files changed, 32 insertions, 5 deletions
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 9ee94827728d..f9df7dd2609a 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h | |||
@@ -27,6 +27,7 @@ struct ucounts; | |||
27 | enum ucount_type { | 27 | enum ucount_type { |
28 | UCOUNT_USER_NAMESPACES, | 28 | UCOUNT_USER_NAMESPACES, |
29 | UCOUNT_PID_NAMESPACES, | 29 | UCOUNT_PID_NAMESPACES, |
30 | UCOUNT_UTS_NAMESPACES, | ||
30 | UCOUNT_COUNTS, | 31 | UCOUNT_COUNTS, |
31 | }; | 32 | }; |
32 | 33 | ||
diff --git a/include/linux/utsname.h b/include/linux/utsname.h index 5093f58ae192..60f0bb83b313 100644 --- a/include/linux/utsname.h +++ b/include/linux/utsname.h | |||
@@ -24,6 +24,7 @@ struct uts_namespace { | |||
24 | struct kref kref; | 24 | struct kref kref; |
25 | struct new_utsname name; | 25 | struct new_utsname name; |
26 | struct user_namespace *user_ns; | 26 | struct user_namespace *user_ns; |
27 | struct ucounts *ucounts; | ||
27 | struct ns_common ns; | 28 | struct ns_common ns; |
28 | }; | 29 | }; |
29 | extern struct uts_namespace init_uts_ns; | 30 | extern struct uts_namespace init_uts_ns; |
diff --git a/kernel/ucount.c b/kernel/ucount.c index 66eca94e4ada..866850e2eb92 100644 --- a/kernel/ucount.c +++ b/kernel/ucount.c | |||
@@ -69,6 +69,7 @@ static int int_max = INT_MAX; | |||
69 | static struct ctl_table user_table[] = { | 69 | static struct ctl_table user_table[] = { |
70 | UCOUNT_ENTRY("max_user_namespaces"), | 70 | UCOUNT_ENTRY("max_user_namespaces"), |
71 | UCOUNT_ENTRY("max_pid_namespaces"), | 71 | UCOUNT_ENTRY("max_pid_namespaces"), |
72 | UCOUNT_ENTRY("max_uts_namespaces"), | ||
72 | { } | 73 | { } |
73 | }; | 74 | }; |
74 | #endif /* CONFIG_SYSCTL */ | 75 | #endif /* CONFIG_SYSCTL */ |
diff --git a/kernel/utsname.c b/kernel/utsname.c index 831ea7108232..f3b0bb4ac3ba 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c | |||
@@ -17,6 +17,16 @@ | |||
17 | #include <linux/user_namespace.h> | 17 | #include <linux/user_namespace.h> |
18 | #include <linux/proc_ns.h> | 18 | #include <linux/proc_ns.h> |
19 | 19 | ||
20 | static struct ucounts *inc_uts_namespaces(struct user_namespace *ns) | ||
21 | { | ||
22 | return inc_ucount(ns, current_euid(), UCOUNT_UTS_NAMESPACES); | ||
23 | } | ||
24 | |||
25 | static void dec_uts_namespaces(struct ucounts *ucounts) | ||
26 | { | ||
27 | dec_ucount(ucounts, UCOUNT_UTS_NAMESPACES); | ||
28 | } | ||
29 | |||
20 | static struct uts_namespace *create_uts_ns(void) | 30 | static struct uts_namespace *create_uts_ns(void) |
21 | { | 31 | { |
22 | struct uts_namespace *uts_ns; | 32 | struct uts_namespace *uts_ns; |
@@ -36,18 +46,24 @@ static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns, | |||
36 | struct uts_namespace *old_ns) | 46 | struct uts_namespace *old_ns) |
37 | { | 47 | { |
38 | struct uts_namespace *ns; | 48 | struct uts_namespace *ns; |
49 | struct ucounts *ucounts; | ||
39 | int err; | 50 | int err; |
40 | 51 | ||
52 | err = -ENFILE; | ||
53 | ucounts = inc_uts_namespaces(user_ns); | ||
54 | if (!ucounts) | ||
55 | goto fail; | ||
56 | |||
57 | err = -ENOMEM; | ||
41 | ns = create_uts_ns(); | 58 | ns = create_uts_ns(); |
42 | if (!ns) | 59 | if (!ns) |
43 | return ERR_PTR(-ENOMEM); | 60 | goto fail_dec; |
44 | 61 | ||
45 | err = ns_alloc_inum(&ns->ns); | 62 | err = ns_alloc_inum(&ns->ns); |
46 | if (err) { | 63 | if (err) |
47 | kfree(ns); | 64 | goto fail_free; |
48 | return ERR_PTR(err); | ||
49 | } | ||
50 | 65 | ||
66 | ns->ucounts = ucounts; | ||
51 | ns->ns.ops = &utsns_operations; | 67 | ns->ns.ops = &utsns_operations; |
52 | 68 | ||
53 | down_read(&uts_sem); | 69 | down_read(&uts_sem); |
@@ -55,6 +71,13 @@ static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns, | |||
55 | ns->user_ns = get_user_ns(user_ns); | 71 | ns->user_ns = get_user_ns(user_ns); |
56 | up_read(&uts_sem); | 72 | up_read(&uts_sem); |
57 | return ns; | 73 | return ns; |
74 | |||
75 | fail_free: | ||
76 | kfree(ns); | ||
77 | fail_dec: | ||
78 | dec_uts_namespaces(ucounts); | ||
79 | fail: | ||
80 | return ERR_PTR(err); | ||
58 | } | 81 | } |
59 | 82 | ||
60 | /* | 83 | /* |
@@ -85,6 +108,7 @@ void free_uts_ns(struct kref *kref) | |||
85 | struct uts_namespace *ns; | 108 | struct uts_namespace *ns; |
86 | 109 | ||
87 | ns = container_of(kref, struct uts_namespace, kref); | 110 | ns = container_of(kref, struct uts_namespace, kref); |
111 | dec_uts_namespaces(ns->ucounts); | ||
88 | put_user_ns(ns->user_ns); | 112 | put_user_ns(ns->user_ns); |
89 | ns_free_inum(&ns->ns); | 113 | ns_free_inum(&ns->ns); |
90 | kfree(ns); | 114 | kfree(ns); |