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