summaryrefslogtreecommitdiffstats
path: root/meta
diff options
context:
space:
mode:
authorRoss Burton <ross.burton@intel.com>2017-07-18 17:04:08 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2017-07-19 11:30:16 +0100
commit50af58cedb3153f058d23a0a9584cf69bdcce81b (patch)
tree7bbef9c9bde1645ee70301d9a0aa48466dde7dc3 /meta
parentfcf4312731c8c54a7318dd326a2183037aca3380 (diff)
downloadpoky-50af58cedb3153f058d23a0a9584cf69bdcce81b.tar.gz
systemd: refuse to load units with errors (CVE-2017-1000082)
If a unit has a statement such as User=0day where the username exists but is strictly speaking invalid, the unit will be started as the root user instead. Backport a patch from upstream to mitigate this by refusing to start units such as this. (From OE-Core rev: 549cb941c5b19909fb00f2bef9c04172ca1c162d) Signed-off-by: Ross Burton <ross.burton@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta')
-rw-r--r--meta/recipes-core/systemd/systemd/0001-core-load-fragment-refuse-units-with-errors-in-certa.patch329
-rw-r--r--meta/recipes-core/systemd/systemd_232.bb1
2 files changed, 330 insertions, 0 deletions
diff --git a/meta/recipes-core/systemd/systemd/0001-core-load-fragment-refuse-units-with-errors-in-certa.patch b/meta/recipes-core/systemd/systemd/0001-core-load-fragment-refuse-units-with-errors-in-certa.patch
new file mode 100644
index 0000000000..80948b2cee
--- /dev/null
+++ b/meta/recipes-core/systemd/systemd/0001-core-load-fragment-refuse-units-with-errors-in-certa.patch
@@ -0,0 +1,329 @@
1If a user is created with a strictly-speaking invalid name such as '0day' and a
2unit created to run as that user, systemd rejects the username and runs the unit
3as root.
4
5CVE: CVE-2017-1000082
6Upstream-Status: Backport
7Signed-off-by: Ross Burton <ross.burton@intel.com>
8
9From d8e1310e1ed7b6f122bc7eb8ba061fbd088783c0 Mon Sep 17 00:00:00 2001
10From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
11Date: Thu, 6 Jul 2017 13:28:19 -0400
12Subject: [PATCH] core/load-fragment: refuse units with errors in certain
13 directives
14
15If an error is encountered in any of the Exec* lines, WorkingDirectory,
16SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
17units), User, or Group, refuse to load the unit. If the config stanza
18has support, ignore the failure if '-' is present.
19
20For those configuration directives, even if we started the unit, it's
21pretty likely that it'll do something unexpected (like write files
22in a wrong place, or with a wrong context, or run with wrong permissions,
23etc). It seems better to refuse to start the unit and have the admin
24clean up the configuration without giving the service a chance to mess
25up stuff.
26
27Note that all "security" options that restrict what the unit can do
28(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
29PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
30only supplementary, and are not always available depending on the architecture
31and compilation options, so unit authors have to make sure that the service
32runs correctly without them anyway.
33
34Fixes #6237, #6277.
35
36Signed-off-by: Ross Burton <ross.burton@intel.com>
37---
38 src/core/load-fragment.c | 104 ++++++++++++++++++++++++++++------------------
39 src/test/test-unit-file.c | 14 +++----
40 2 files changed, 70 insertions(+), 48 deletions(-)
41
42diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
43index cbc826809..2047974f4 100644
44--- a/src/core/load-fragment.c
45+++ b/src/core/load-fragment.c
46@@ -630,20 +630,28 @@ int config_parse_exec(
47
48 if (isempty(f)) {
49 /* First word is either "-" or "@" with no command. */
50- log_syntax(unit, LOG_ERR, filename, line, 0, "Empty path in command line, ignoring: \"%s\"", rvalue);
51- return 0;
52+ log_syntax(unit, LOG_ERR, filename, line, 0,
53+ "Empty path in command line%s: \"%s\"",
54+ ignore ? ", ignoring" : "", rvalue);
55+ return ignore ? 0 : -ENOEXEC;
56 }
57 if (!string_is_safe(f)) {
58- log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path contains special characters, ignoring: %s", rvalue);
59- return 0;
60+ log_syntax(unit, LOG_ERR, filename, line, 0,
61+ "Executable path contains special characters%s: %s",
62+ ignore ? ", ignoring" : "", rvalue);
63+ return ignore ? 0 : -ENOEXEC;
64 }
65 if (!path_is_absolute(f)) {
66- log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path is not absolute, ignoring: %s", rvalue);
67- return 0;
68+ log_syntax(unit, LOG_ERR, filename, line, 0,
69+ "Executable path is not absolute%s: %s",
70+ ignore ? ", ignoring" : "", rvalue);
71+ return ignore ? 0 : -ENOEXEC;
72 }
73 if (endswith(f, "/")) {
74- log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path specifies a directory, ignoring: %s", rvalue);
75- return 0;
76+ log_syntax(unit, LOG_ERR, filename, line, 0,
77+ "Executable path specifies a directory%s: %s",
78+ ignore ? ", ignoring" : "", rvalue);
79+ return ignore ? 0 : -ENOEXEC;
80 }
81
82 if (f == firstword) {
83@@ -699,7 +707,7 @@ int config_parse_exec(
84 if (r == 0)
85 break;
86 else if (r < 0)
87- return 0;
88+ return ignore ? 0 : -ENOEXEC;
89
90 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
91 return log_oom();
92@@ -709,8 +717,10 @@ int config_parse_exec(
93 }
94
95 if (!n || !n[0]) {
96- log_syntax(unit, LOG_ERR, filename, line, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue);
97- return 0;
98+ log_syntax(unit, LOG_ERR, filename, line, 0,
99+ "Empty executable name or zeroeth argument%s: %s",
100+ ignore ? ", ignoring" : "", rvalue);
101+ return ignore ? 0 : -ENOEXEC;
102 }
103
104 nce = new0(ExecCommand, 1);
105@@ -1315,8 +1325,10 @@ int config_parse_exec_selinux_context(
106
107 r = unit_name_printf(u, rvalue, &k);
108 if (r < 0) {
109- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
110- return 0;
111+ log_syntax(unit, LOG_ERR, filename, line, r,
112+ "Failed to resolve specifiers%s: %m",
113+ ignore ? ", ignoring" : "");
114+ return ignore ? 0 : -ENOEXEC;
115 }
116
117 free(c->selinux_context);
118@@ -1363,8 +1375,10 @@ int config_parse_exec_apparmor_profile(
119
120 r = unit_name_printf(u, rvalue, &k);
121 if (r < 0) {
122- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
123- return 0;
124+ log_syntax(unit, LOG_ERR, filename, line, r,
125+ "Failed to resolve specifiers%s: %m",
126+ ignore ? ", ignoring" : "");
127+ return ignore ? 0 : -ENOEXEC;
128 }
129
130 free(c->apparmor_profile);
131@@ -1411,8 +1425,10 @@ int config_parse_exec_smack_process_label(
132
133 r = unit_name_printf(u, rvalue, &k);
134 if (r < 0) {
135- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
136- return 0;
137+ log_syntax(unit, LOG_ERR, filename, line, r,
138+ "Failed to resolve specifiers%s: %m",
139+ ignore ? ", ignoring" : "");
140+ return ignore ? 0 : -ENOEXEC;
141 }
142
143 free(c->smack_process_label);
144@@ -1630,19 +1646,19 @@ int config_parse_socket_service(
145
146 r = unit_name_printf(UNIT(s), rvalue, &p);
147 if (r < 0) {
148- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
149- return 0;
150+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers: %s", rvalue);
151+ return -ENOEXEC;
152 }
153
154 if (!endswith(p, ".service")) {
155- log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue);
156- return 0;
157+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service: %s", rvalue);
158+ return -ENOEXEC;
159 }
160
161 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
162 if (r < 0) {
163- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
164- return 0;
165+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s: %s", rvalue, bus_error_message(&error, r));
166+ return -ENOEXEC;
167 }
168
169 unit_ref_set(&s->service, x);
170@@ -1893,13 +1909,13 @@ int config_parse_user_group(
171
172 r = unit_full_printf(u, rvalue, &k);
173 if (r < 0) {
174- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
175- return 0;
176+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", rvalue);
177+ return -ENOEXEC;
178 }
179
180 if (!valid_user_group_name_or_id(k)) {
181- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID, ignoring: %s", k);
182- return 0;
183+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
184+ return -ENOEXEC;
185 }
186
187 n = k;
188@@ -1957,19 +1973,19 @@ int config_parse_user_group_strv(
189 if (r == -ENOMEM)
190 return log_oom();
191 if (r < 0) {
192- log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
193- break;
194+ log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax: %s", rvalue);
195+ return -ENOEXEC;
196 }
197
198 r = unit_full_printf(u, word, &k);
199 if (r < 0) {
200- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", word);
201- continue;
202+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", word);
203+ return -ENOEXEC;
204 }
205
206 if (!valid_user_group_name_or_id(k)) {
207- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID, ignoring: %s", k);
208- continue;
209+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
210+ return -ENOEXEC;
211 }
212
213 r = strv_push(users, k);
214@@ -2128,25 +2144,28 @@ int config_parse_working_directory(
215
216 r = unit_full_printf(u, rvalue, &k);
217 if (r < 0) {
218- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue);
219- return 0;
220+ log_syntax(unit, LOG_ERR, filename, line, r,
221+ "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
222+ rvalue, missing_ok ? ", ignoring" : "");
223+ return missing_ok ? 0 : -ENOEXEC;
224 }
225
226 path_kill_slashes(k);
227
228 if (!utf8_is_valid(k)) {
229 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
230- return 0;
231+ return missing_ok ? 0 : -ENOEXEC;
232 }
233
234 if (!path_is_absolute(k)) {
235- log_syntax(unit, LOG_ERR, filename, line, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue);
236- return 0;
237+ log_syntax(unit, LOG_ERR, filename, line, 0,
238+ "Working directory path '%s' is not absolute%s.",
239+ rvalue, missing_ok ? ", ignoring" : "");
240+ return missing_ok ? 0 : -ENOEXEC;
241 }
242
243- free_and_replace(c->working_directory, k);
244-
245 c->working_directory_home = false;
246+ free_and_replace(c->working_directory, k);
247 }
248
249 c->working_directory_missing_ok = missing_ok;
250@@ -4228,8 +4247,11 @@ int unit_load_fragment(Unit *u) {
251 return r;
252
253 r = load_from_path(u, k);
254- if (r < 0)
255+ if (r < 0) {
256+ if (r == -ENOEXEC)
257+ log_unit_notice(u, "Unit configuration has fatal error, unit will not be started.");
258 return r;
259+ }
260
261 if (u->load_state == UNIT_STUB) {
262 SET_FOREACH(t, u->names, i) {
263diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
264index 12f48bf43..fd797b587 100644
265--- a/src/test/test-unit-file.c
266+++ b/src/test/test-unit-file.c
267@@ -146,7 +146,7 @@ static void test_config_parse_exec(void) {
268 r = config_parse_exec(NULL, "fake", 4, "section", 1,
269 "LValue", 0, "/RValue/ argv0 r1",
270 &c, u);
271- assert_se(r == 0);
272+ assert_se(r == -ENOEXEC);
273 assert_se(c1->command_next == NULL);
274
275 log_info("/* honour_argv0 */");
276@@ -161,7 +161,7 @@ static void test_config_parse_exec(void) {
277 r = config_parse_exec(NULL, "fake", 3, "section", 1,
278 "LValue", 0, "@/RValue",
279 &c, u);
280- assert_se(r == 0);
281+ assert_se(r == -ENOEXEC);
282 assert_se(c1->command_next == NULL);
283
284 log_info("/* no command, whitespace only, reset */");
285@@ -220,7 +220,7 @@ static void test_config_parse_exec(void) {
286 "-@/RValue argv0 r1 ; ; "
287 "/goo/goo boo",
288 &c, u);
289- assert_se(r >= 0);
290+ assert_se(r == -ENOEXEC);
291 c1 = c1->command_next;
292 check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
293
294@@ -374,7 +374,7 @@ static void test_config_parse_exec(void) {
295 r = config_parse_exec(NULL, "fake", 4, "section", 1,
296 "LValue", 0, path,
297 &c, u);
298- assert_se(r == 0);
299+ assert_se(r == -ENOEXEC);
300 assert_se(c1->command_next == NULL);
301 }
302
303@@ -401,21 +401,21 @@ static void test_config_parse_exec(void) {
304 r = config_parse_exec(NULL, "fake", 4, "section", 1,
305 "LValue", 0, "/path\\",
306 &c, u);
307- assert_se(r == 0);
308+ assert_se(r == -ENOEXEC);
309 assert_se(c1->command_next == NULL);
310
311 log_info("/* missing ending ' */");
312 r = config_parse_exec(NULL, "fake", 4, "section", 1,
313 "LValue", 0, "/path 'foo",
314 &c, u);
315- assert_se(r == 0);
316+ assert_se(r == -ENOEXEC);
317 assert_se(c1->command_next == NULL);
318
319 log_info("/* missing ending ' with trailing backslash */");
320 r = config_parse_exec(NULL, "fake", 4, "section", 1,
321 "LValue", 0, "/path 'foo\\",
322 &c, u);
323- assert_se(r == 0);
324+ assert_se(r == -ENOEXEC);
325 assert_se(c1->command_next == NULL);
326
327 log_info("/* invalid space between modifiers */");
328--
3292.11.0
diff --git a/meta/recipes-core/systemd/systemd_232.bb b/meta/recipes-core/systemd/systemd_232.bb
index e8292ab388..9c533ea4c8 100644
--- a/meta/recipes-core/systemd/systemd_232.bb
+++ b/meta/recipes-core/systemd/systemd_232.bb
@@ -32,6 +32,7 @@ SRC_URI += " \
32 file://0020-back-port-233-don-t-use-the-unified-hierarchy-for-the-systemd.patch \ 32 file://0020-back-port-233-don-t-use-the-unified-hierarchy-for-the-systemd.patch \
33 file://0021-build-sys-check-for-lz4-in-the-old-and-new-numbering.patch \ 33 file://0021-build-sys-check-for-lz4-in-the-old-and-new-numbering.patch \
34 file://0022-parse-util-Do-not-include-unneeded-xlocale.h.patch \ 34 file://0022-parse-util-Do-not-include-unneeded-xlocale.h.patch \
35 file://0001-core-load-fragment-refuse-units-with-errors-in-certa.patch \
35 " 36 "
36SRC_URI_append_qemuall = " file://0001-core-device.c-Change-the-default-device-timeout-to-2.patch" 37SRC_URI_append_qemuall = " file://0001-core-device.c-Change-the-default-device-timeout-to-2.patch"
37 38