Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <grp.h>
4 : #include <pwd.h>
5 : #include <stdio.h>
6 : #include <sys/prctl.h>
7 : #include <sys/types.h>
8 :
9 : #include "capability-util.h"
10 : #include "cpu-set-util.h"
11 : #include "errno-list.h"
12 : #include "fileio.h"
13 : #include "fs-util.h"
14 : #include "macro.h"
15 : #include "manager.h"
16 : #include "missing_prctl.h"
17 : #include "mkdir.h"
18 : #include "path-util.h"
19 : #include "rm-rf.h"
20 : #if HAVE_SECCOMP
21 : #include "seccomp-util.h"
22 : #endif
23 : #include "service.h"
24 : #include "stat-util.h"
25 : #include "test-helper.h"
26 : #include "tests.h"
27 : #include "unit.h"
28 : #include "user-util.h"
29 : #include "util.h"
30 : #include "virt.h"
31 :
32 : static bool can_unshare;
33 :
34 : typedef void (*test_function_t)(Manager *m);
35 :
36 0 : static int cld_dumped_to_killed(int code) {
37 : /* Depending on the system, seccomp version, … some signals might result in dumping, others in plain
38 : * killing. Let's ignore the difference here, and map both cases to CLD_KILLED */
39 0 : return code == CLD_DUMPED ? CLD_KILLED : code;
40 : }
41 :
42 0 : static void wait_for_service_finish(Manager *m, Unit *unit) {
43 0 : Service *service = NULL;
44 : usec_t ts;
45 0 : usec_t timeout = 2 * USEC_PER_MINUTE;
46 :
47 0 : assert_se(m);
48 0 : assert_se(unit);
49 :
50 0 : service = SERVICE(unit);
51 0 : printf("%s\n", unit->id);
52 0 : exec_context_dump(&service->exec_context, stdout, "\t");
53 0 : ts = now(CLOCK_MONOTONIC);
54 0 : while (!IN_SET(service->state, SERVICE_DEAD, SERVICE_FAILED)) {
55 : int r;
56 : usec_t n;
57 :
58 0 : r = sd_event_run(m->event, 100 * USEC_PER_MSEC);
59 0 : assert_se(r >= 0);
60 :
61 0 : n = now(CLOCK_MONOTONIC);
62 0 : if (ts + timeout < n) {
63 0 : log_error("Test timeout when testing %s", unit->id);
64 0 : r = unit_kill(unit, KILL_ALL, SIGKILL, NULL);
65 0 : if (r < 0)
66 0 : log_error_errno(r, "Failed to kill %s: %m", unit->id);
67 0 : exit(EXIT_FAILURE);
68 : }
69 : }
70 0 : }
71 :
72 0 : static void check_main_result(const char *func, Manager *m, Unit *unit, int status_expected, int code_expected) {
73 0 : Service *service = NULL;
74 :
75 0 : assert_se(m);
76 0 : assert_se(unit);
77 :
78 0 : wait_for_service_finish(m, unit);
79 :
80 0 : service = SERVICE(unit);
81 0 : exec_status_dump(&service->main_exec_status, stdout, "\t");
82 :
83 0 : if (cld_dumped_to_killed(service->main_exec_status.code) != cld_dumped_to_killed(code_expected)) {
84 0 : log_error("%s: %s: exit code %d, expected %d",
85 : func, unit->id,
86 : service->main_exec_status.code, code_expected);
87 0 : abort();
88 : }
89 :
90 0 : if (service->main_exec_status.status != status_expected) {
91 0 : log_error("%s: %s: exit status %d, expected %d",
92 : func, unit->id,
93 : service->main_exec_status.status, status_expected);
94 0 : abort();
95 : }
96 0 : }
97 :
98 0 : static void check_service_result(const char *func, Manager *m, Unit *unit, ServiceResult result_expected) {
99 0 : Service *service = NULL;
100 :
101 0 : assert_se(m);
102 0 : assert_se(unit);
103 :
104 0 : wait_for_service_finish(m, unit);
105 :
106 0 : service = SERVICE(unit);
107 :
108 0 : if (service->result != result_expected) {
109 0 : log_error("%s: %s: service end result %s, expected %s",
110 : func, unit->id,
111 : service_result_to_string(service->result),
112 : service_result_to_string(result_expected));
113 0 : abort();
114 : }
115 0 : }
116 :
117 0 : static bool check_nobody_user_and_group(void) {
118 : static int cache = -1;
119 : struct passwd *p;
120 : struct group *g;
121 :
122 0 : if (cache >= 0)
123 0 : return !!cache;
124 :
125 0 : if (!synthesize_nobody())
126 0 : goto invalid;
127 :
128 0 : p = getpwnam(NOBODY_USER_NAME);
129 0 : if (!p ||
130 0 : !streq(p->pw_name, NOBODY_USER_NAME) ||
131 0 : p->pw_uid != UID_NOBODY ||
132 0 : p->pw_gid != GID_NOBODY)
133 0 : goto invalid;
134 :
135 0 : p = getpwuid(UID_NOBODY);
136 0 : if (!p ||
137 0 : !streq(p->pw_name, NOBODY_USER_NAME) ||
138 0 : p->pw_uid != UID_NOBODY ||
139 0 : p->pw_gid != GID_NOBODY)
140 0 : goto invalid;
141 :
142 0 : g = getgrnam(NOBODY_GROUP_NAME);
143 0 : if (!g ||
144 0 : !streq(g->gr_name, NOBODY_GROUP_NAME) ||
145 0 : g->gr_gid != GID_NOBODY)
146 0 : goto invalid;
147 :
148 0 : g = getgrgid(GID_NOBODY);
149 0 : if (!g ||
150 0 : !streq(g->gr_name, NOBODY_GROUP_NAME) ||
151 0 : g->gr_gid != GID_NOBODY)
152 0 : goto invalid;
153 :
154 0 : cache = 1;
155 0 : return true;
156 :
157 0 : invalid:
158 0 : cache = 0;
159 0 : return false;
160 : }
161 :
162 0 : static bool check_user_has_group_with_same_name(const char *name) {
163 : struct passwd *p;
164 : struct group *g;
165 :
166 0 : assert(name);
167 :
168 0 : p = getpwnam(name);
169 0 : if (!p ||
170 0 : !streq(p->pw_name, name))
171 0 : return false;
172 :
173 0 : g = getgrgid(p->pw_gid);
174 0 : if (!g ||
175 0 : !streq(g->gr_name, name))
176 0 : return false;
177 :
178 0 : return true;
179 : }
180 :
181 0 : static bool is_inaccessible_available(void) {
182 : const char *p;
183 :
184 0 : FOREACH_STRING(p,
185 : "/run/systemd/inaccessible/reg",
186 : "/run/systemd/inaccessible/dir",
187 : "/run/systemd/inaccessible/chr",
188 : "/run/systemd/inaccessible/blk",
189 : "/run/systemd/inaccessible/fifo",
190 : "/run/systemd/inaccessible/sock"
191 : ) {
192 0 : if (access(p, F_OK) < 0)
193 0 : return false;
194 : }
195 :
196 0 : return true;
197 : }
198 :
199 0 : static void test(const char *func, Manager *m, const char *unit_name, int status_expected, int code_expected) {
200 : Unit *unit;
201 :
202 0 : assert_se(unit_name);
203 :
204 0 : assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
205 0 : assert_se(unit_start(unit) >= 0);
206 0 : check_main_result(func, m, unit, status_expected, code_expected);
207 0 : }
208 :
209 0 : static void test_service(const char *func, Manager *m, const char *unit_name, ServiceResult result_expected) {
210 : Unit *unit;
211 :
212 0 : assert_se(unit_name);
213 :
214 0 : assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
215 0 : assert_se(unit_start(unit) >= 0);
216 0 : check_service_result(func, m, unit, result_expected);
217 0 : }
218 :
219 0 : static void test_exec_bindpaths(Manager *m) {
220 0 : assert_se(mkdir_p("/tmp/test-exec-bindpaths", 0755) >= 0);
221 0 : assert_se(mkdir_p("/tmp/test-exec-bindreadonlypaths", 0755) >= 0);
222 :
223 0 : test(__func__, m, "exec-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
224 :
225 0 : (void) rm_rf("/tmp/test-exec-bindpaths", REMOVE_ROOT|REMOVE_PHYSICAL);
226 0 : (void) rm_rf("/tmp/test-exec-bindreadonlypaths", REMOVE_ROOT|REMOVE_PHYSICAL);
227 0 : }
228 :
229 0 : static void test_exec_cpuaffinity(Manager *m) {
230 0 : _cleanup_(cpu_set_reset) CPUSet c = {};
231 :
232 0 : assert_se(cpu_set_realloc(&c, 8192) >= 0); /* just allocate the maximum possible size */
233 0 : assert_se(sched_getaffinity(0, c.allocated, c.set) >= 0);
234 :
235 0 : if (!CPU_ISSET_S(0, c.allocated, c.set)) {
236 0 : log_notice("Cannot use CPU 0, skipping %s", __func__);
237 0 : return;
238 : }
239 :
240 0 : test(__func__, m, "exec-cpuaffinity1.service", 0, CLD_EXITED);
241 0 : test(__func__, m, "exec-cpuaffinity2.service", 0, CLD_EXITED);
242 :
243 0 : if (!CPU_ISSET_S(1, c.allocated, c.set) ||
244 0 : !CPU_ISSET_S(2, c.allocated, c.set)) {
245 0 : log_notice("Cannot use CPU 1 or 2, skipping remaining tests in %s", __func__);
246 0 : return;
247 : }
248 :
249 0 : test(__func__, m, "exec-cpuaffinity3.service", 0, CLD_EXITED);
250 : }
251 :
252 0 : static void test_exec_workingdirectory(Manager *m) {
253 0 : assert_se(mkdir_p("/tmp/test-exec_workingdirectory", 0755) >= 0);
254 :
255 0 : test(__func__, m, "exec-workingdirectory.service", 0, CLD_EXITED);
256 0 : test(__func__, m, "exec-workingdirectory-trailing-dot.service", 0, CLD_EXITED);
257 :
258 0 : (void) rm_rf("/tmp/test-exec_workingdirectory", REMOVE_ROOT|REMOVE_PHYSICAL);
259 0 : }
260 :
261 0 : static void test_exec_personality(Manager *m) {
262 : #if defined(__x86_64__)
263 0 : test(__func__, m, "exec-personality-x86-64.service", 0, CLD_EXITED);
264 :
265 : #elif defined(__s390__)
266 : test(__func__, m, "exec-personality-s390.service", 0, CLD_EXITED);
267 :
268 : #elif defined(__powerpc64__)
269 : # if __BYTE_ORDER == __BIG_ENDIAN
270 : test(__func__, m, "exec-personality-ppc64.service", 0, CLD_EXITED);
271 : # else
272 : test(__func__, m, "exec-personality-ppc64le.service", 0, CLD_EXITED);
273 : # endif
274 :
275 : #elif defined(__aarch64__)
276 : test(__func__, m, "exec-personality-aarch64.service", 0, CLD_EXITED);
277 :
278 : #elif defined(__i386__)
279 : test(__func__, m, "exec-personality-x86.service", 0, CLD_EXITED);
280 : #else
281 : log_notice("Unknown personality, skipping %s", __func__);
282 : #endif
283 0 : }
284 :
285 0 : static void test_exec_ignoresigpipe(Manager *m) {
286 0 : test(__func__, m, "exec-ignoresigpipe-yes.service", 0, CLD_EXITED);
287 0 : test(__func__, m, "exec-ignoresigpipe-no.service", SIGPIPE, CLD_KILLED);
288 0 : }
289 :
290 0 : static void test_exec_privatetmp(Manager *m) {
291 0 : assert_se(touch("/tmp/test-exec_privatetmp") >= 0);
292 :
293 0 : test(__func__, m, "exec-privatetmp-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
294 0 : test(__func__, m, "exec-privatetmp-no.service", 0, CLD_EXITED);
295 :
296 0 : unlink("/tmp/test-exec_privatetmp");
297 0 : }
298 :
299 0 : static void test_exec_privatedevices(Manager *m) {
300 : int r;
301 :
302 0 : if (detect_container() > 0) {
303 0 : log_notice("Testing in container, skipping %s", __func__);
304 0 : return;
305 : }
306 0 : if (!is_inaccessible_available()) {
307 0 : log_notice("Testing without inaccessible, skipping %s", __func__);
308 0 : return;
309 : }
310 :
311 0 : test(__func__, m, "exec-privatedevices-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
312 0 : test(__func__, m, "exec-privatedevices-no.service", 0, CLD_EXITED);
313 0 : test(__func__, m, "exec-privatedevices-disabled-by-prefix.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
314 :
315 : /* We use capsh to test if the capabilities are
316 : * properly set, so be sure that it exists */
317 0 : r = find_binary("capsh", NULL);
318 0 : if (r < 0) {
319 0 : log_notice_errno(r, "Could not find capsh binary, skipping remaining tests in %s: %m", __func__);
320 0 : return;
321 : }
322 :
323 0 : test(__func__, m, "exec-privatedevices-yes-capability-mknod.service", 0, CLD_EXITED);
324 0 : test(__func__, m, "exec-privatedevices-no-capability-mknod.service", 0, CLD_EXITED);
325 0 : test(__func__, m, "exec-privatedevices-yes-capability-sys-rawio.service", 0, CLD_EXITED);
326 0 : test(__func__, m, "exec-privatedevices-no-capability-sys-rawio.service", 0, CLD_EXITED);
327 : }
328 :
329 0 : static void test_exec_protecthome(Manager *m) {
330 0 : if (!can_unshare) {
331 0 : log_notice("Cannot reliably unshare, skipping %s", __func__);
332 0 : return;
333 : }
334 :
335 0 : test(__func__, m, "exec-protecthome-tmpfs-vs-protectsystem-strict.service", 0, CLD_EXITED);
336 : }
337 :
338 0 : static void test_exec_protectkernelmodules(Manager *m) {
339 : int r;
340 :
341 0 : if (detect_container() > 0) {
342 0 : log_notice("Testing in container, skipping %s", __func__);
343 0 : return;
344 : }
345 0 : if (!is_inaccessible_available()) {
346 0 : log_notice("Testing without inaccessible, skipping %s", __func__);
347 0 : return;
348 : }
349 :
350 0 : r = find_binary("capsh", NULL);
351 0 : if (r < 0) {
352 0 : log_notice_errno(r, "Skipping %s, could not find capsh binary: %m", __func__);
353 0 : return;
354 : }
355 :
356 0 : test(__func__, m, "exec-protectkernelmodules-no-capabilities.service", 0, CLD_EXITED);
357 0 : test(__func__, m, "exec-protectkernelmodules-yes-capabilities.service", 0, CLD_EXITED);
358 0 : test(__func__, m, "exec-protectkernelmodules-yes-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
359 : }
360 :
361 0 : static void test_exec_readonlypaths(Manager *m) {
362 :
363 0 : test(__func__, m, "exec-readonlypaths-simple.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
364 :
365 0 : if (path_is_read_only_fs("/var") > 0) {
366 0 : log_notice("Directory /var is readonly, skipping remaining tests in %s", __func__);
367 0 : return;
368 : }
369 :
370 0 : test(__func__, m, "exec-readonlypaths.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
371 0 : test(__func__, m, "exec-readonlypaths-with-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
372 0 : test(__func__, m, "exec-readonlypaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
373 : }
374 :
375 0 : static void test_exec_readwritepaths(Manager *m) {
376 :
377 0 : if (path_is_read_only_fs("/") > 0) {
378 0 : log_notice("Root directory is readonly, skipping %s", __func__);
379 0 : return;
380 : }
381 :
382 0 : test(__func__, m, "exec-readwritepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
383 : }
384 :
385 0 : static void test_exec_inaccessiblepaths(Manager *m) {
386 :
387 0 : if (!is_inaccessible_available()) {
388 0 : log_notice("Testing without inaccessible, skipping %s", __func__);
389 0 : return;
390 : }
391 :
392 0 : test(__func__, m, "exec-inaccessiblepaths-sys.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
393 :
394 0 : if (path_is_read_only_fs("/") > 0) {
395 0 : log_notice("Root directory is readonly, skipping remaining tests in %s", __func__);
396 0 : return;
397 : }
398 :
399 0 : test(__func__, m, "exec-inaccessiblepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
400 : }
401 :
402 0 : static void test_exec_temporaryfilesystem(Manager *m) {
403 :
404 0 : test(__func__, m, "exec-temporaryfilesystem-options.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
405 0 : test(__func__, m, "exec-temporaryfilesystem-ro.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
406 0 : test(__func__, m, "exec-temporaryfilesystem-rw.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
407 0 : test(__func__, m, "exec-temporaryfilesystem-usr.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
408 0 : }
409 :
410 0 : static void test_exec_systemcallfilter(Manager *m) {
411 : #if HAVE_SECCOMP
412 : int r;
413 :
414 0 : if (!is_seccomp_available()) {
415 0 : log_notice("Seccomp not available, skipping %s", __func__);
416 0 : return;
417 : }
418 :
419 0 : test(__func__, m, "exec-systemcallfilter-not-failing.service", 0, CLD_EXITED);
420 0 : test(__func__, m, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED);
421 0 : test(__func__, m, "exec-systemcallfilter-failing.service", SIGSYS, CLD_KILLED);
422 0 : test(__func__, m, "exec-systemcallfilter-failing2.service", SIGSYS, CLD_KILLED);
423 :
424 0 : r = find_binary("python3", NULL);
425 0 : if (r < 0) {
426 0 : log_notice_errno(r, "Skipping remaining tests in %s, could not find python3 binary: %m", __func__);
427 0 : return;
428 : }
429 :
430 0 : test(__func__, m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED);
431 0 : test(__func__, m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED);
432 0 : test(__func__, m, "exec-systemcallfilter-with-errno-multi.service", errno_from_name("EILSEQ"), CLD_EXITED);
433 : #endif
434 : }
435 :
436 0 : static void test_exec_systemcallerrornumber(Manager *m) {
437 : #if HAVE_SECCOMP
438 : int r;
439 :
440 0 : if (!is_seccomp_available()) {
441 0 : log_notice("Seccomp not available, skipping %s", __func__);
442 0 : return;
443 : }
444 :
445 0 : r = find_binary("python3", NULL);
446 0 : if (r < 0) {
447 0 : log_notice_errno(r, "Skipping %s, could not find python3 binary: %m", __func__);
448 0 : return;
449 : }
450 :
451 0 : test(__func__, m, "exec-systemcallerrornumber-name.service", errno_from_name("EACCES"), CLD_EXITED);
452 0 : test(__func__, m, "exec-systemcallerrornumber-number.service", 255, CLD_EXITED);
453 : #endif
454 : }
455 :
456 0 : static void test_exec_restrictnamespaces(Manager *m) {
457 : #if HAVE_SECCOMP
458 0 : if (!is_seccomp_available()) {
459 0 : log_notice("Seccomp not available, skipping %s", __func__);
460 0 : return;
461 : }
462 :
463 0 : test(__func__, m, "exec-restrictnamespaces-no.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
464 0 : test(__func__, m, "exec-restrictnamespaces-yes.service", 1, CLD_EXITED);
465 0 : test(__func__, m, "exec-restrictnamespaces-mnt.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
466 0 : test(__func__, m, "exec-restrictnamespaces-mnt-blacklist.service", 1, CLD_EXITED);
467 0 : test(__func__, m, "exec-restrictnamespaces-merge-and.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
468 0 : test(__func__, m, "exec-restrictnamespaces-merge-or.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
469 0 : test(__func__, m, "exec-restrictnamespaces-merge-all.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
470 : #endif
471 : }
472 :
473 0 : static void test_exec_systemcallfilter_system(Manager *m) {
474 : /* Skip this particular test case when running under ASan, as
475 : * LSan intermittently segfaults when accessing memory right
476 : * after the test finishes. Generally, ASan & LSan don't like
477 : * the seccomp stuff.
478 : */
479 : #if HAVE_SECCOMP && !HAS_FEATURE_ADDRESS_SANITIZER
480 0 : if (!is_seccomp_available()) {
481 0 : log_notice("Seccomp not available, skipping %s", __func__);
482 0 : return;
483 : }
484 :
485 0 : test(__func__, m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED);
486 :
487 0 : if (!check_nobody_user_and_group()) {
488 0 : log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
489 0 : return;
490 : }
491 :
492 0 : if (!STR_IN_SET(NOBODY_USER_NAME, "nobody", "nfsnobody")) {
493 0 : log_notice("Unsupported nobody user name '%s', skipping remaining tests in %s", NOBODY_USER_NAME, __func__);
494 0 : return;
495 : }
496 :
497 0 : test(__func__, m, "exec-systemcallfilter-system-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
498 : #endif
499 : }
500 :
501 0 : static void test_exec_user(Manager *m) {
502 0 : test(__func__, m, "exec-user.service", 0, CLD_EXITED);
503 :
504 0 : if (!check_nobody_user_and_group()) {
505 0 : log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
506 0 : return;
507 : }
508 :
509 0 : if (!STR_IN_SET(NOBODY_USER_NAME, "nobody", "nfsnobody")) {
510 0 : log_notice("Unsupported nobody user name '%s', skipping remaining tests in %s", NOBODY_USER_NAME, __func__);
511 0 : return;
512 : }
513 :
514 0 : test(__func__, m, "exec-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
515 : }
516 :
517 0 : static void test_exec_group(Manager *m) {
518 0 : test(__func__, m, "exec-group.service", 0, CLD_EXITED);
519 :
520 0 : if (!check_nobody_user_and_group()) {
521 0 : log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
522 0 : return;
523 : }
524 :
525 0 : if (!STR_IN_SET(NOBODY_GROUP_NAME, "nobody", "nfsnobody", "nogroup")) {
526 0 : log_notice("Unsupported nobody group name '%s', skipping remaining tests in %s", NOBODY_GROUP_NAME, __func__);
527 0 : return;
528 : }
529 :
530 0 : test(__func__, m, "exec-group-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
531 : }
532 :
533 0 : static void test_exec_supplementarygroups(Manager *m) {
534 0 : test(__func__, m, "exec-supplementarygroups.service", 0, CLD_EXITED);
535 0 : test(__func__, m, "exec-supplementarygroups-single-group.service", 0, CLD_EXITED);
536 0 : test(__func__, m, "exec-supplementarygroups-single-group-user.service", 0, CLD_EXITED);
537 0 : test(__func__, m, "exec-supplementarygroups-multiple-groups-default-group-user.service", 0, CLD_EXITED);
538 0 : test(__func__, m, "exec-supplementarygroups-multiple-groups-withgid.service", 0, CLD_EXITED);
539 0 : test(__func__, m, "exec-supplementarygroups-multiple-groups-withuid.service", 0, CLD_EXITED);
540 0 : }
541 :
542 0 : static void test_exec_dynamicuser(Manager *m) {
543 :
544 0 : test(__func__, m, "exec-dynamicuser-fixeduser.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
545 0 : if (check_user_has_group_with_same_name("adm"))
546 0 : test(__func__, m, "exec-dynamicuser-fixeduser-adm.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
547 0 : if (check_user_has_group_with_same_name("games"))
548 0 : test(__func__, m, "exec-dynamicuser-fixeduser-games.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
549 0 : test(__func__, m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
550 0 : test(__func__, m, "exec-dynamicuser-supplementarygroups.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
551 0 : test(__func__, m, "exec-dynamicuser-statedir.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
552 :
553 0 : (void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
554 0 : (void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
555 0 : (void) rm_rf("/var/lib/private/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
556 0 : (void) rm_rf("/var/lib/private/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
557 :
558 0 : test(__func__, m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
559 0 : test(__func__, m, "exec-dynamicuser-statedir-migrate-step2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
560 :
561 0 : (void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
562 0 : (void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
563 0 : (void) rm_rf("/var/lib/private/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
564 0 : (void) rm_rf("/var/lib/private/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
565 0 : }
566 :
567 0 : static void test_exec_environment(Manager *m) {
568 0 : test(__func__, m, "exec-environment-no-substitute.service", 0, CLD_EXITED);
569 0 : test(__func__, m, "exec-environment.service", 0, CLD_EXITED);
570 0 : test(__func__, m, "exec-environment-multiple.service", 0, CLD_EXITED);
571 0 : test(__func__, m, "exec-environment-empty.service", 0, CLD_EXITED);
572 0 : }
573 :
574 0 : static void test_exec_environmentfile(Manager *m) {
575 : static const char e[] =
576 : "VAR1='word1 word2'\n"
577 : "VAR2=word3 \n"
578 : "# comment1\n"
579 : "\n"
580 : "; comment2\n"
581 : " ; # comment3\n"
582 : "line without an equal\n"
583 : "VAR3='$word 5 6'\n"
584 : "VAR4='new\nline'\n"
585 : "VAR5=password\\with\\backslashes";
586 : int r;
587 :
588 0 : r = write_string_file("/tmp/test-exec_environmentfile.conf", e, WRITE_STRING_FILE_CREATE);
589 0 : assert_se(r == 0);
590 :
591 0 : test(__func__, m, "exec-environmentfile.service", 0, CLD_EXITED);
592 :
593 0 : (void) unlink("/tmp/test-exec_environmentfile.conf");
594 0 : }
595 :
596 0 : static void test_exec_passenvironment(Manager *m) {
597 : /* test-execute runs under MANAGER_USER which, by default, forwards all
598 : * variables present in the environment, but only those that are
599 : * present _at the time it is created_!
600 : *
601 : * So these PassEnvironment checks are still expected to work, since we
602 : * are ensuring the variables are not present at manager creation (they
603 : * are unset explicitly in main) and are only set here.
604 : *
605 : * This is still a good approximation of how a test for MANAGER_SYSTEM
606 : * would work.
607 : */
608 0 : assert_se(setenv("VAR1", "word1 word2", 1) == 0);
609 0 : assert_se(setenv("VAR2", "word3", 1) == 0);
610 0 : assert_se(setenv("VAR3", "$word 5 6", 1) == 0);
611 0 : assert_se(setenv("VAR4", "new\nline", 1) == 0);
612 0 : assert_se(setenv("VAR5", "passwordwithbackslashes", 1) == 0);
613 0 : test(__func__, m, "exec-passenvironment.service", 0, CLD_EXITED);
614 0 : test(__func__, m, "exec-passenvironment-repeated.service", 0, CLD_EXITED);
615 0 : test(__func__, m, "exec-passenvironment-empty.service", 0, CLD_EXITED);
616 0 : assert_se(unsetenv("VAR1") == 0);
617 0 : assert_se(unsetenv("VAR2") == 0);
618 0 : assert_se(unsetenv("VAR3") == 0);
619 0 : assert_se(unsetenv("VAR4") == 0);
620 0 : assert_se(unsetenv("VAR5") == 0);
621 0 : test(__func__, m, "exec-passenvironment-absent.service", 0, CLD_EXITED);
622 0 : }
623 :
624 0 : static void test_exec_umask(Manager *m) {
625 0 : test(__func__, m, "exec-umask-default.service", 0, CLD_EXITED);
626 0 : test(__func__, m, "exec-umask-0177.service", 0, CLD_EXITED);
627 0 : }
628 :
629 0 : static void test_exec_runtimedirectory(Manager *m) {
630 0 : test(__func__, m, "exec-runtimedirectory.service", 0, CLD_EXITED);
631 0 : test(__func__, m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
632 0 : test(__func__, m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
633 :
634 0 : if (!check_nobody_user_and_group()) {
635 0 : log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
636 0 : return;
637 : }
638 :
639 0 : if (!STR_IN_SET(NOBODY_GROUP_NAME, "nobody", "nfsnobody", "nogroup")) {
640 0 : log_notice("Unsupported nobody group name '%s', skipping remaining tests in %s", NOBODY_GROUP_NAME, __func__);
641 0 : return;
642 : }
643 :
644 0 : test(__func__, m, "exec-runtimedirectory-owner-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
645 : }
646 :
647 0 : static void test_exec_capabilityboundingset(Manager *m) {
648 : int r;
649 :
650 0 : r = find_binary("capsh", NULL);
651 0 : if (r < 0) {
652 0 : log_notice_errno(r, "Skipping %s, could not find capsh binary: %m", __func__);
653 0 : return;
654 : }
655 :
656 0 : if (have_effective_cap(CAP_CHOWN) <= 0 ||
657 0 : have_effective_cap(CAP_FOWNER) <= 0 ||
658 0 : have_effective_cap(CAP_KILL) <= 0) {
659 0 : log_notice("Skipping %s, this process does not have enough capabilities", __func__);
660 0 : return;
661 : }
662 :
663 0 : test(__func__, m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED);
664 0 : test(__func__, m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED);
665 0 : test(__func__, m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED);
666 0 : test(__func__, m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
667 : }
668 :
669 0 : static void test_exec_basic(Manager *m) {
670 0 : test(__func__, m, "exec-basic.service", 0, CLD_EXITED);
671 0 : }
672 :
673 0 : static void test_exec_ambientcapabilities(Manager *m) {
674 : int r;
675 :
676 : /* Check if the kernel has support for ambient capabilities. Run
677 : * the tests only if that's the case. Clearing all ambient
678 : * capabilities is fine, since we are expecting them to be unset
679 : * in the first place for the tests. */
680 0 : r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
681 0 : if (r < 0 && IN_SET(errno, EINVAL, EOPNOTSUPP, ENOSYS)) {
682 0 : log_notice("Skipping %s, the kernel does not support ambient capabilities", __func__);
683 0 : return;
684 : }
685 :
686 0 : if (have_effective_cap(CAP_CHOWN) <= 0 ||
687 0 : have_effective_cap(CAP_NET_RAW) <= 0) {
688 0 : log_notice("Skipping %s, this process does not have enough capabilities", __func__);
689 0 : return;
690 : }
691 :
692 0 : test(__func__, m, "exec-ambientcapabilities.service", 0, CLD_EXITED);
693 0 : test(__func__, m, "exec-ambientcapabilities-merge.service", 0, CLD_EXITED);
694 :
695 0 : if (!check_nobody_user_and_group()) {
696 0 : log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
697 0 : return;
698 : }
699 :
700 0 : if (!STR_IN_SET(NOBODY_USER_NAME, "nobody", "nfsnobody")) {
701 0 : log_notice("Unsupported nobody user name '%s', skipping remaining tests in %s", NOBODY_USER_NAME, __func__);
702 0 : return;
703 : }
704 :
705 0 : test(__func__, m, "exec-ambientcapabilities-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
706 0 : test(__func__, m, "exec-ambientcapabilities-merge-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
707 : }
708 :
709 0 : static void test_exec_privatenetwork(Manager *m) {
710 : int r;
711 :
712 0 : r = find_binary("ip", NULL);
713 0 : if (r < 0) {
714 0 : log_notice_errno(r, "Skipping %s, could not find ip binary: %m", __func__);
715 0 : return;
716 : }
717 :
718 0 : test(__func__, m, "exec-privatenetwork-yes.service", can_unshare ? 0 : EXIT_NETWORK, CLD_EXITED);
719 : }
720 :
721 0 : static void test_exec_oomscoreadjust(Manager *m) {
722 0 : test(__func__, m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED);
723 :
724 0 : if (detect_container() > 0) {
725 0 : log_notice("Testing in container, skipping remaining tests in %s", __func__);
726 0 : return;
727 : }
728 0 : test(__func__, m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
729 : }
730 :
731 0 : static void test_exec_ioschedulingclass(Manager *m) {
732 0 : test(__func__, m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED);
733 0 : test(__func__, m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED);
734 0 : test(__func__, m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
735 :
736 0 : if (detect_container() > 0) {
737 0 : log_notice("Testing in container, skipping remaining tests in %s", __func__);
738 0 : return;
739 : }
740 0 : test(__func__, m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
741 : }
742 :
743 0 : static void test_exec_unsetenvironment(Manager *m) {
744 0 : test(__func__, m, "exec-unsetenvironment.service", 0, CLD_EXITED);
745 0 : }
746 :
747 0 : static void test_exec_specifier(Manager *m) {
748 0 : test(__func__, m, "exec-specifier.service", 0, CLD_EXITED);
749 0 : test(__func__, m, "exec-specifier@foo-bar.service", 0, CLD_EXITED);
750 0 : test(__func__, m, "exec-specifier-interpolation.service", 0, CLD_EXITED);
751 0 : }
752 :
753 0 : static void test_exec_standardinput(Manager *m) {
754 0 : test(__func__, m, "exec-standardinput-data.service", 0, CLD_EXITED);
755 0 : test(__func__, m, "exec-standardinput-file.service", 0, CLD_EXITED);
756 0 : }
757 :
758 0 : static void test_exec_standardoutput(Manager *m) {
759 0 : test(__func__, m, "exec-standardoutput-file.service", 0, CLD_EXITED);
760 0 : }
761 :
762 0 : static void test_exec_standardoutput_append(Manager *m) {
763 0 : test(__func__, m, "exec-standardoutput-append.service", 0, CLD_EXITED);
764 0 : }
765 :
766 0 : static void test_exec_condition(Manager *m) {
767 0 : test_service(__func__, m, "exec-condition-failed.service", SERVICE_FAILURE_EXIT_CODE);
768 0 : test_service(__func__, m, "exec-condition-skip.service", SERVICE_SKIP_CONDITION);
769 0 : }
770 :
771 : typedef struct test_entry {
772 : test_function_t f;
773 : const char *name;
774 : } test_entry;
775 :
776 : #define entry(x) {x, #x}
777 :
778 0 : static int run_tests(UnitFileScope scope, const test_entry tests[], char **patterns) {
779 0 : const test_entry *test = NULL;
780 0 : _cleanup_(manager_freep) Manager *m = NULL;
781 : int r;
782 :
783 0 : assert_se(tests);
784 :
785 0 : r = manager_new(scope, MANAGER_TEST_RUN_BASIC, &m);
786 0 : if (MANAGER_SKIP_TEST(r))
787 0 : return log_tests_skipped_errno(r, "manager_new");
788 0 : assert_se(r >= 0);
789 0 : assert_se(manager_startup(m, NULL, NULL) >= 0);
790 :
791 0 : for (test = tests; test && test->f; test++)
792 0 : if (strv_fnmatch_or_empty(patterns, test->name, FNM_NOESCAPE))
793 0 : test->f(m);
794 : else
795 0 : log_info("Skipping %s because it does not match any pattern.", test->name);
796 :
797 0 : return 0;
798 : }
799 :
800 1 : int main(int argc, char *argv[]) {
801 1 : _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
802 1 : _cleanup_free_ char *test_execute_path = NULL;
803 :
804 : static const test_entry user_tests[] = {
805 : entry(test_exec_basic),
806 : entry(test_exec_ambientcapabilities),
807 : entry(test_exec_bindpaths),
808 : entry(test_exec_capabilityboundingset),
809 : entry(test_exec_condition),
810 : entry(test_exec_cpuaffinity),
811 : entry(test_exec_environment),
812 : entry(test_exec_environmentfile),
813 : entry(test_exec_group),
814 : entry(test_exec_ignoresigpipe),
815 : entry(test_exec_inaccessiblepaths),
816 : entry(test_exec_ioschedulingclass),
817 : entry(test_exec_oomscoreadjust),
818 : entry(test_exec_passenvironment),
819 : entry(test_exec_personality),
820 : entry(test_exec_privatedevices),
821 : entry(test_exec_privatenetwork),
822 : entry(test_exec_privatetmp),
823 : entry(test_exec_protecthome),
824 : entry(test_exec_protectkernelmodules),
825 : entry(test_exec_readonlypaths),
826 : entry(test_exec_readwritepaths),
827 : entry(test_exec_restrictnamespaces),
828 : entry(test_exec_runtimedirectory),
829 : entry(test_exec_standardinput),
830 : entry(test_exec_standardoutput),
831 : entry(test_exec_standardoutput_append),
832 : entry(test_exec_supplementarygroups),
833 : entry(test_exec_systemcallerrornumber),
834 : entry(test_exec_systemcallfilter),
835 : entry(test_exec_temporaryfilesystem),
836 : entry(test_exec_umask),
837 : entry(test_exec_unsetenvironment),
838 : entry(test_exec_user),
839 : entry(test_exec_workingdirectory),
840 : {},
841 : };
842 : static const test_entry system_tests[] = {
843 : entry(test_exec_dynamicuser),
844 : entry(test_exec_specifier),
845 : entry(test_exec_systemcallfilter_system),
846 : {},
847 : };
848 : int r;
849 :
850 1 : test_setup_logging(LOG_DEBUG);
851 :
852 : #if HAS_FEATURE_ADDRESS_SANITIZER
853 : if (is_run_on_travis_ci()) {
854 : log_notice("Running on TravisCI under ASan, skipping, see https://github.com/systemd/systemd/issues/10696");
855 : return EXIT_TEST_SKIP;
856 : }
857 : #endif
858 :
859 1 : (void) unsetenv("USER");
860 1 : (void) unsetenv("LOGNAME");
861 1 : (void) unsetenv("SHELL");
862 1 : (void) unsetenv("HOME");
863 :
864 1 : can_unshare = have_namespaces();
865 :
866 : /* It is needed otherwise cgroup creation fails */
867 1 : if (getuid() != 0)
868 1 : return log_tests_skipped("not root");
869 :
870 0 : r = enter_cgroup_subroot();
871 0 : if (r == -ENOMEDIUM)
872 0 : return log_tests_skipped("cgroupfs not available");
873 :
874 0 : assert_se(runtime_dir = setup_fake_runtime_dir());
875 0 : test_execute_path = path_join(get_testdata_dir(), "test-execute");
876 0 : assert_se(set_unit_path(test_execute_path) >= 0);
877 :
878 : /* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test
879 : * cases, otherwise (and if they are present in the environment),
880 : * `manager_default_environment` will copy them into the default
881 : * environment which is passed to each created job, which will make the
882 : * tests that expect those not to be present to fail.
883 : */
884 0 : assert_se(unsetenv("VAR1") == 0);
885 0 : assert_se(unsetenv("VAR2") == 0);
886 0 : assert_se(unsetenv("VAR3") == 0);
887 :
888 0 : r = run_tests(UNIT_FILE_USER, user_tests, argv + 1);
889 0 : if (r != 0)
890 0 : return r;
891 :
892 0 : r = run_tests(UNIT_FILE_SYSTEM, system_tests, argv + 1);
893 0 : if (r != 0)
894 0 : return r;
895 :
896 : #if HAVE_SECCOMP
897 : /* The following tests are for 1beab8b0d0ff2d7d1436b52d4a0c3d56dc908962. */
898 0 : if (!is_seccomp_available()) {
899 0 : log_notice("Seccomp not available, skipping unshare() filtered tests.");
900 0 : return 0;
901 : }
902 :
903 0 : _cleanup_hashmap_free_ Hashmap *s = NULL;
904 0 : assert_se(s = hashmap_new(NULL));
905 0 : r = seccomp_syscall_resolve_name("unshare");
906 0 : assert_se(r != __NR_SCMP_ERROR);
907 0 : assert_se(hashmap_put(s, UINT32_TO_PTR(r + 1), INT_TO_PTR(-1)) >= 0);
908 0 : assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EOPNOTSUPP), true) >= 0);
909 0 : assert_se(unshare(CLONE_NEWNS) < 0);
910 0 : assert_se(errno == EOPNOTSUPP);
911 :
912 0 : can_unshare = false;
913 :
914 0 : r = run_tests(UNIT_FILE_USER, user_tests, argv + 1);
915 0 : if (r != 0)
916 0 : return r;
917 :
918 0 : return run_tests(UNIT_FILE_SYSTEM, system_tests, argv + 1);
919 : #else
920 : return 0;
921 : #endif
922 : }
|