]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-execute.c
verify: use manager_load_startable_unit_or_warn() to load units for verification
[thirdparty/systemd.git] / src / test / test-execute.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
281e05b6
RC
2/***
3 This file is part of systemd.
4
5 Copyright 2014 Ronny Chevalier
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
cc7fa4fb
RC
21#include <grp.h>
22#include <pwd.h>
ff4ca461 23#include <stdio.h>
70d7aea5 24#include <sys/prctl.h>
ff4ca461 25#include <sys/types.h>
281e05b6 26
b7856f92 27#include "capability-util.h"
4e79aeaa 28#include "cpu-set-util.h"
b4891260 29#include "errno-list.h"
03bd70dd 30#include "fileio.h"
f4f15635 31#include "fs-util.h"
281e05b6 32#include "macro.h"
f4f15635 33#include "manager.h"
281e05b6 34#include "mkdir.h"
ff4ca461 35#include "path-util.h"
c6878637 36#include "rm-rf.h"
349cc4a5 37#if HAVE_SECCOMP
83f12b27
FS
38#include "seccomp-util.h"
39#endif
34b86909 40#include "stat-util.h"
8b3aa503 41#include "test-helper.h"
cc100a5a 42#include "tests.h"
f4f15635 43#include "unit.h"
57c2efa0 44#include "user-util.h"
f4f15635 45#include "util.h"
4dd4cb8f 46#include "virt.h"
281e05b6
RC
47
48typedef void (*test_function_t)(Manager *m);
49
50static void check(Manager *m, Unit *unit, int status_expected, int code_expected) {
51 Service *service = NULL;
52 usec_t ts;
8adb3d63 53 usec_t timeout = 2 * USEC_PER_MINUTE;
281e05b6
RC
54
55 assert_se(m);
56 assert_se(unit);
57
58 service = SERVICE(unit);
59 printf("%s\n", unit->id);
60 exec_context_dump(&service->exec_context, stdout, "\t");
61 ts = now(CLOCK_MONOTONIC);
ec2ce0c5 62 while (!IN_SET(service->state, SERVICE_DEAD, SERVICE_FAILED)) {
281e05b6
RC
63 int r;
64 usec_t n;
65
66 r = sd_event_run(m->event, 100 * USEC_PER_MSEC);
67 assert_se(r >= 0);
68
69 n = now(CLOCK_MONOTONIC);
70 if (ts + timeout < n) {
71 log_error("Test timeout when testing %s", unit->id);
72 exit(EXIT_FAILURE);
73 }
74 }
75 exec_status_dump(&service->main_exec_status, stdout, "\t");
76 assert_se(service->main_exec_status.status == status_expected);
77 assert_se(service->main_exec_status.code == code_expected);
78}
79
57c2efa0
YW
80static bool check_nobody_user_and_group(void) {
81 static int cache = -1;
82 struct passwd *p;
83 struct group *g;
84
85 if (cache >= 0)
86 return !!cache;
87
88 if (!synthesize_nobody())
89 goto invalid;
90
91 p = getpwnam(NOBODY_USER_NAME);
92 if (!p ||
93 !streq(p->pw_name, NOBODY_USER_NAME) ||
94 p->pw_uid != UID_NOBODY ||
95 p->pw_gid != GID_NOBODY)
96 goto invalid;
97
98 p = getpwuid(UID_NOBODY);
99 if (!p ||
100 !streq(p->pw_name, NOBODY_USER_NAME) ||
101 p->pw_uid != UID_NOBODY ||
102 p->pw_gid != GID_NOBODY)
103 goto invalid;
104
105 g = getgrnam(NOBODY_GROUP_NAME);
106 if (!g ||
107 !streq(g->gr_name, NOBODY_GROUP_NAME) ||
108 g->gr_gid != GID_NOBODY)
109 goto invalid;
110
111 g = getgrgid(GID_NOBODY);
112 if (!g ||
113 !streq(g->gr_name, NOBODY_GROUP_NAME) ||
114 g->gr_gid != GID_NOBODY)
115 goto invalid;
116
117 cache = 1;
118 return true;
119
120invalid:
121 cache = 0;
122 return false;
123}
124
6086d2da
DP
125static bool is_inaccessible_available(void) {
126 char *p;
127
128 FOREACH_STRING(p,
129 "/run/systemd/inaccessible/reg",
130 "/run/systemd/inaccessible/dir",
131 "/run/systemd/inaccessible/chr",
132 "/run/systemd/inaccessible/blk",
133 "/run/systemd/inaccessible/fifo",
134 "/run/systemd/inaccessible/sock"
135 ) {
136 if (access(p, F_OK) < 0)
137 return false;
138 }
139
140 return true;
141}
142
281e05b6
RC
143static void test(Manager *m, const char *unit_name, int status_expected, int code_expected) {
144 Unit *unit;
145
146 assert_se(unit_name);
147
ba412430 148 assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
281e05b6
RC
149 assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
150 check(m, unit, status_expected, code_expected);
151}
152
f0e018e7
YW
153static void test_exec_bindpaths(Manager *m) {
154 assert_se(mkdir_p("/tmp/test-exec-bindpaths", 0755) >= 0);
155 assert_se(mkdir_p("/tmp/test-exec-bindreadonlypaths", 0755) >= 0);
d053b72b 156
f0e018e7 157 test(m, "exec-bindpaths.service", 0, CLD_EXITED);
d053b72b 158
f0e018e7
YW
159 (void) rm_rf("/tmp/test-exec-bindpaths", REMOVE_ROOT|REMOVE_PHYSICAL);
160 (void) rm_rf("/tmp/test-exec-bindreadonlypaths", REMOVE_ROOT|REMOVE_PHYSICAL);
d053b72b
YW
161}
162
4e79aeaa
YW
163static void test_exec_cpuaffinity(Manager *m) {
164 _cleanup_cpu_free_ cpu_set_t *c = NULL;
165 unsigned n;
166
167 assert_se(c = cpu_set_malloc(&n));
168 assert_se(sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0);
169
170 if (CPU_ISSET_S(0, CPU_ALLOC_SIZE(n), c) == 0) {
171 log_notice("Cannot use CPU 0, skipping %s", __func__);
172 return;
173 }
174
175 test(m, "exec-cpuaffinity1.service", 0, CLD_EXITED);
176 test(m, "exec-cpuaffinity2.service", 0, CLD_EXITED);
177
178 if (CPU_ISSET_S(1, CPU_ALLOC_SIZE(n), c) == 0 ||
179 CPU_ISSET_S(2, CPU_ALLOC_SIZE(n), c) == 0) {
180 log_notice("Cannot use CPU 1 or 2, skipping remaining tests in %s", __func__);
181 return;
182 }
183
184 test(m, "exec-cpuaffinity3.service", 0, CLD_EXITED);
185}
186
281e05b6
RC
187static void test_exec_workingdirectory(Manager *m) {
188 assert_se(mkdir_p("/tmp/test-exec_workingdirectory", 0755) >= 0);
189
190 test(m, "exec-workingdirectory.service", 0, CLD_EXITED);
191
c6878637 192 (void) rm_rf("/tmp/test-exec_workingdirectory", REMOVE_ROOT|REMOVE_PHYSICAL);
281e05b6
RC
193}
194
195static void test_exec_personality(Manager *m) {
281e05b6
RC
196#if defined(__x86_64__)
197 test(m, "exec-personality-x86-64.service", 0, CLD_EXITED);
7517f51e
HB
198
199#elif defined(__s390__)
200 test(m, "exec-personality-s390.service", 0, CLD_EXITED);
201
12591863
JS
202#elif defined(__powerpc64__)
203# if __BYTE_ORDER == __BIG_ENDIAN
204 test(m, "exec-personality-ppc64.service", 0, CLD_EXITED);
205# else
206 test(m, "exec-personality-ppc64le.service", 0, CLD_EXITED);
207# endif
208
209#elif defined(__aarch64__)
210 test(m, "exec-personality-aarch64.service", 0, CLD_EXITED);
211
5798eb4c 212#elif defined(__i386__)
7517f51e 213 test(m, "exec-personality-x86.service", 0, CLD_EXITED);
f0e018e7
YW
214#else
215 log_notice("Unknown personality, skipping %s", __func__);
281e05b6
RC
216#endif
217}
218
219static void test_exec_ignoresigpipe(Manager *m) {
220 test(m, "exec-ignoresigpipe-yes.service", 0, CLD_EXITED);
221 test(m, "exec-ignoresigpipe-no.service", SIGPIPE, CLD_KILLED);
222}
223
224static void test_exec_privatetmp(Manager *m) {
225 assert_se(touch("/tmp/test-exec_privatetmp") >= 0);
226
227 test(m, "exec-privatetmp-yes.service", 0, CLD_EXITED);
228 test(m, "exec-privatetmp-no.service", 0, CLD_EXITED);
229
230 unlink("/tmp/test-exec_privatetmp");
231}
232
233static void test_exec_privatedevices(Manager *m) {
f0e018e7
YW
234 int r;
235
4dd4cb8f 236 if (detect_container() > 0) {
f0e018e7 237 log_notice("Testing in container, skipping %s", __func__);
4dd4cb8f
SM
238 return;
239 }
6086d2da 240 if (!is_inaccessible_available()) {
f0e018e7 241 log_notice("Testing without inaccessible, skipping %s", __func__);
6086d2da
DP
242 return;
243 }
244
281e05b6
RC
245 test(m, "exec-privatedevices-yes.service", 0, CLD_EXITED);
246 test(m, "exec-privatedevices-no.service", 0, CLD_EXITED);
6086d2da 247
0608ba98
ZJS
248 /* We use capsh to test if the capabilities are
249 * properly set, so be sure that it exists */
250 r = find_binary("capsh", NULL);
251 if (r < 0) {
5cd33ccc 252 log_notice_errno(r, "Could not find capsh binary, skipping remaining tests in %s: %m", __func__);
6086d2da
DP
253 return;
254 }
255
615a1f4b
DH
256 test(m, "exec-privatedevices-yes-capability-mknod.service", 0, CLD_EXITED);
257 test(m, "exec-privatedevices-no-capability-mknod.service", 0, CLD_EXITED);
625d8769
DH
258 test(m, "exec-privatedevices-yes-capability-sys-rawio.service", 0, CLD_EXITED);
259 test(m, "exec-privatedevices-no-capability-sys-rawio.service", 0, CLD_EXITED);
615a1f4b
DH
260}
261
4982dbcc 262static void test_exec_protectkernelmodules(Manager *m) {
0608ba98
ZJS
263 int r;
264
3ae33295 265 if (detect_container() > 0) {
f0e018e7 266 log_notice("Testing in container, skipping %s", __func__);
3ae33295
DH
267 return;
268 }
6086d2da 269 if (!is_inaccessible_available()) {
f0e018e7 270 log_notice("Testing without inaccessible, skipping %s", __func__);
6086d2da
DP
271 return;
272 }
3ae33295 273
0608ba98
ZJS
274 r = find_binary("capsh", NULL);
275 if (r < 0) {
5cd33ccc 276 log_notice_errno(r, "Skipping %s, could not find capsh binary: %m", __func__);
0608ba98
ZJS
277 return;
278 }
279
3ae33295
DH
280 test(m, "exec-protectkernelmodules-no-capabilities.service", 0, CLD_EXITED);
281 test(m, "exec-protectkernelmodules-yes-capabilities.service", 0, CLD_EXITED);
4982dbcc 282 test(m, "exec-protectkernelmodules-yes-mount-propagation.service", 0, CLD_EXITED);
3ae33295
DH
283}
284
f78b36f0 285static void test_exec_readonlypaths(Manager *m) {
34b86909 286
f0e018e7
YW
287 test(m, "exec-readonlypaths-simple.service", 0, CLD_EXITED);
288
289 if (path_is_read_only_fs("/var") > 0) {
290 log_notice("Directory /var is readonly, skipping remaining tests in %s", __func__);
34b86909 291 return;
f0e018e7 292 }
34b86909 293
f78b36f0 294 test(m, "exec-readonlypaths.service", 0, CLD_EXITED);
cdfbd1fb 295 test(m, "exec-readonlypaths-mount-propagation.service", 0, CLD_EXITED);
23fd04e9 296 test(m, "exec-readonlypaths-with-bindpaths.service", 0, CLD_EXITED);
cdfbd1fb
DH
297}
298
299static void test_exec_readwritepaths(Manager *m) {
34b86909 300
f0e018e7
YW
301 if (path_is_read_only_fs("/") > 0) {
302 log_notice("Root directory is readonly, skipping %s", __func__);
34b86909 303 return;
f0e018e7 304 }
34b86909 305
cdfbd1fb
DH
306 test(m, "exec-readwritepaths-mount-propagation.service", 0, CLD_EXITED);
307}
308
309static void test_exec_inaccessiblepaths(Manager *m) {
34b86909 310
f0e018e7
YW
311 if (!is_inaccessible_available()) {
312 log_notice("Testing without inaccessible, skipping %s", __func__);
34b86909 313 return;
f0e018e7 314 }
34b86909 315
f0e018e7 316 test(m, "exec-inaccessiblepaths-proc.service", 0, CLD_EXITED);
f78b36f0 317
f0e018e7
YW
318 if (path_is_read_only_fs("/") > 0) {
319 log_notice("Root directory is readonly, skipping remaining tests in %s", __func__);
af4af186
EV
320 return;
321 }
322
f0e018e7 323 test(m, "exec-inaccessiblepaths-mount-propagation.service", 0, CLD_EXITED);
c090d74d
TR
324}
325
4cac89bd
YW
326static void test_exec_temporaryfilesystem(Manager *m) {
327
328 test(m, "exec-temporaryfilesystem-options.service", 0, CLD_EXITED);
329 test(m, "exec-temporaryfilesystem-ro.service", 0, CLD_EXITED);
330 test(m, "exec-temporaryfilesystem-rw.service", 0, CLD_EXITED);
331 test(m, "exec-temporaryfilesystem-usr.service", 0, CLD_EXITED);
332}
333
281e05b6 334static void test_exec_systemcallfilter(Manager *m) {
349cc4a5 335#if HAVE_SECCOMP
f0e018e7
YW
336 if (!is_seccomp_available()) {
337 log_notice("Seccomp not available, skipping %s", __func__);
83f12b27 338 return;
f0e018e7
YW
339 }
340
281e05b6
RC
341 test(m, "exec-systemcallfilter-not-failing.service", 0, CLD_EXITED);
342 test(m, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED);
343 test(m, "exec-systemcallfilter-failing.service", SIGSYS, CLD_KILLED);
344 test(m, "exec-systemcallfilter-failing2.service", SIGSYS, CLD_KILLED);
b4891260
YW
345 test(m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED);
346 test(m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED);
281e05b6
RC
347#endif
348}
349
350static void test_exec_systemcallerrornumber(Manager *m) {
349cc4a5 351#if HAVE_SECCOMP
f0e018e7
YW
352 if (!is_seccomp_available()) {
353 log_notice("Seccomp not available, skipping %s", __func__);
7a18854f 354 return;
f0e018e7
YW
355 }
356
7a18854f
YW
357 test(m, "exec-systemcallerrornumber-name.service", errno_from_name("EACCES"), CLD_EXITED);
358 test(m, "exec-systemcallerrornumber-number.service", 255, CLD_EXITED);
281e05b6
RC
359#endif
360}
361
f0e018e7 362static void test_exec_restrictnamespaces(Manager *m) {
349cc4a5 363#if HAVE_SECCOMP
f0e018e7
YW
364 if (!is_seccomp_available()) {
365 log_notice("Seccomp not available, skipping %s", __func__);
97e60383 366 return;
f0e018e7 367 }
97e60383 368
f0e018e7
YW
369 test(m, "exec-restrictnamespaces-no.service", 0, CLD_EXITED);
370 test(m, "exec-restrictnamespaces-yes.service", 1, CLD_EXITED);
371 test(m, "exec-restrictnamespaces-mnt.service", 0, CLD_EXITED);
372 test(m, "exec-restrictnamespaces-mnt-blacklist.service", 1, CLD_EXITED);
97e60383
DH
373#endif
374}
375
f0e018e7 376static void test_exec_systemcallfilter_system(Manager *m) {
349cc4a5 377#if HAVE_SECCOMP
f0e018e7
YW
378 if (!is_seccomp_available()) {
379 log_notice("Seccomp not available, skipping %s", __func__);
83f12b27 380 return;
f0e018e7 381 }
57c2efa0 382
69b07407
YW
383 test(m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED);
384
57c2efa0 385 if (!check_nobody_user_and_group()) {
5cd33ccc 386 log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
57c2efa0
YW
387 return;
388 }
389
69b07407 390 if (!STR_IN_SET(NOBODY_USER_NAME, "nobody", "nfsnobody")) {
5cd33ccc 391 log_notice("Unsupported nobody user name '%s', skipping remaining tests in %s", NOBODY_USER_NAME, __func__);
69b07407
YW
392 return;
393 }
394
395 test(m, "exec-systemcallfilter-system-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
19c0b0b9
RC
396#endif
397}
398
281e05b6 399static void test_exec_user(Manager *m) {
69b07407
YW
400 test(m, "exec-user.service", 0, CLD_EXITED);
401
57c2efa0 402 if (!check_nobody_user_and_group()) {
5cd33ccc 403 log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
57c2efa0
YW
404 return;
405 }
406
69b07407 407 if (!STR_IN_SET(NOBODY_USER_NAME, "nobody", "nfsnobody")) {
5cd33ccc 408 log_notice("Unsupported nobody user name '%s', skipping remaining tests in %s", NOBODY_USER_NAME, __func__);
69b07407
YW
409 return;
410 }
411
412 test(m, "exec-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
281e05b6
RC
413}
414
415static void test_exec_group(Manager *m) {
69b07407
YW
416 test(m, "exec-group.service", 0, CLD_EXITED);
417
57c2efa0 418 if (!check_nobody_user_and_group()) {
5cd33ccc 419 log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
57c2efa0
YW
420 return;
421 }
422
69b07407 423 if (!STR_IN_SET(NOBODY_GROUP_NAME, "nobody", "nfsnobody", "nogroup")) {
5cd33ccc 424 log_notice("Unsupported nobody group name '%s', skipping remaining tests in %s", NOBODY_GROUP_NAME, __func__);
69b07407
YW
425 return;
426 }
427
428 test(m, "exec-group-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
281e05b6
RC
429}
430
f0e018e7 431static void test_exec_supplementarygroups(Manager *m) {
86b838ea 432 test(m, "exec-supplementarygroups.service", 0, CLD_EXITED);
bf9ace96
DH
433 test(m, "exec-supplementarygroups-single-group.service", 0, CLD_EXITED);
434 test(m, "exec-supplementarygroups-single-group-user.service", 0, CLD_EXITED);
50ca7a35
DH
435 test(m, "exec-supplementarygroups-multiple-groups-default-group-user.service", 0, CLD_EXITED);
436 test(m, "exec-supplementarygroups-multiple-groups-withgid.service", 0, CLD_EXITED);
437 test(m, "exec-supplementarygroups-multiple-groups-withuid.service", 0, CLD_EXITED);
86b838ea
DH
438}
439
f0e018e7 440static void test_exec_dynamicuser(Manager *m) {
2b9ac11e
DH
441 test(m, "exec-dynamicuser-fixeduser.service", 0, CLD_EXITED);
442 test(m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", 0, CLD_EXITED);
5c67067f 443 test(m, "exec-dynamicuser-supplementarygroups.service", 0, CLD_EXITED);
f0e018e7 444 test(m, "exec-dynamicuser-statedir.service", 0, CLD_EXITED);
028f3a7f
YW
445
446 test(m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
447 test(m, "exec-dynamicuser-statedir-migrate-step2.service", 0, CLD_EXITED);
448 (void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
449 (void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
450 (void) rm_rf("/var/lib/private/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
451 (void) rm_rf("/var/lib/private/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
2b9ac11e
DH
452}
453
281e05b6
RC
454static void test_exec_environment(Manager *m) {
455 test(m, "exec-environment.service", 0, CLD_EXITED);
456 test(m, "exec-environment-multiple.service", 0, CLD_EXITED);
457 test(m, "exec-environment-empty.service", 0, CLD_EXITED);
458}
459
03bd70dd
RC
460static void test_exec_environmentfile(Manager *m) {
461 static const char e[] =
462 "VAR1='word1 word2'\n"
463 "VAR2=word3 \n"
464 "# comment1\n"
465 "\n"
466 "; comment2\n"
467 " ; # comment3\n"
468 "line without an equal\n"
9b796f35
FB
469 "VAR3='$word 5 6'\n"
470 "VAR4='new\nline'\n";
03bd70dd
RC
471 int r;
472
473 r = write_string_file("/tmp/test-exec_environmentfile.conf", e, WRITE_STRING_FILE_CREATE);
474 assert_se(r == 0);
475
476 test(m, "exec-environmentfile.service", 0, CLD_EXITED);
477
f0e018e7 478 (void) unlink("/tmp/test-exec_environmentfile.conf");
03bd70dd
RC
479}
480
4c80d201 481static void test_exec_passenvironment(Manager *m) {
e1abca2e
FB
482 /* test-execute runs under MANAGER_USER which, by default, forwards all
483 * variables present in the environment, but only those that are
484 * present _at the time it is created_!
485 *
486 * So these PassEnvironment checks are still expected to work, since we
487 * are ensuring the variables are not present at manager creation (they
488 * are unset explicitly in main) and are only set here.
489 *
490 * This is still a good approximation of how a test for MANAGER_SYSTEM
491 * would work.
492 */
4c80d201
FB
493 assert_se(setenv("VAR1", "word1 word2", 1) == 0);
494 assert_se(setenv("VAR2", "word3", 1) == 0);
495 assert_se(setenv("VAR3", "$word 5 6", 1) == 0);
9b796f35 496 assert_se(setenv("VAR4", "new\nline", 1) == 0);
4c80d201
FB
497 test(m, "exec-passenvironment.service", 0, CLD_EXITED);
498 test(m, "exec-passenvironment-repeated.service", 0, CLD_EXITED);
499 test(m, "exec-passenvironment-empty.service", 0, CLD_EXITED);
500 assert_se(unsetenv("VAR1") == 0);
501 assert_se(unsetenv("VAR2") == 0);
502 assert_se(unsetenv("VAR3") == 0);
9b796f35 503 assert_se(unsetenv("VAR4") == 0);
4c80d201
FB
504 test(m, "exec-passenvironment-absent.service", 0, CLD_EXITED);
505}
506
27c5347c
RC
507static void test_exec_umask(Manager *m) {
508 test(m, "exec-umask-default.service", 0, CLD_EXITED);
509 test(m, "exec-umask-0177.service", 0, CLD_EXITED);
510}
511
cc3ddc85
RC
512static void test_exec_runtimedirectory(Manager *m) {
513 test(m, "exec-runtimedirectory.service", 0, CLD_EXITED);
514 test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
69b07407 515 test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
57c2efa0
YW
516
517 if (!check_nobody_user_and_group()) {
5cd33ccc 518 log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
69b07407
YW
519 return;
520 }
521
522 if (!STR_IN_SET(NOBODY_GROUP_NAME, "nobody", "nfsnobody", "nogroup")) {
5cd33ccc 523 log_notice("Unsupported nobody group name '%s', skipping remaining tests in %s", NOBODY_GROUP_NAME, __func__);
57c2efa0
YW
524 return;
525 }
526
69b07407 527 test(m, "exec-runtimedirectory-owner-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
ff4ca461
RC
528}
529
530static void test_exec_capabilityboundingset(Manager *m) {
531 int r;
532
ff4ca461
RC
533 r = find_binary("capsh", NULL);
534 if (r < 0) {
5cd33ccc 535 log_notice_errno(r, "Skipping %s, could not find capsh binary: %m", __func__);
ff4ca461
RC
536 return;
537 }
538
b7856f92
YW
539 if (have_effective_cap(CAP_CHOWN) <= 0 ||
540 have_effective_cap(CAP_FOWNER) <= 0 ||
541 have_effective_cap(CAP_KILL) <= 0) {
542 log_notice("Skipping %s, this process does not have enough capabilities", __func__);
543 return;
544 }
545
ff4ca461
RC
546 test(m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED);
547 test(m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED);
548 test(m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED);
549 test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
cc3ddc85
RC
550}
551
b6dc25ee 552static void test_exec_ambientcapabilities(Manager *m) {
70d7aea5
IP
553 int r;
554
555 /* Check if the kernel has support for ambient capabilities. Run
556 * the tests only if that's the case. Clearing all ambient
557 * capabilities is fine, since we are expecting them to be unset
558 * in the first place for the tests. */
559 r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
f0e018e7 560 if (r < 0 && IN_SET(errno, EINVAL, EOPNOTSUPP, ENOSYS)) {
5cd33ccc 561 log_notice("Skipping %s, the kernel does not support ambient capabilities", __func__);
f0e018e7
YW
562 return;
563 }
564
e5ba1d32 565 if (have_effective_cap(CAP_CHOWN) <= 0 ||
b7856f92
YW
566 have_effective_cap(CAP_NET_RAW) <= 0) {
567 log_notice("Skipping %s, this process does not have enough capabilities", __func__);
568 return;
569 }
570
b6dc25ee
YW
571 test(m, "exec-ambientcapabilities.service", 0, CLD_EXITED);
572 test(m, "exec-ambientcapabilities-merge.service", 0, CLD_EXITED);
69b07407 573
57c2efa0 574 if (!check_nobody_user_and_group()) {
5cd33ccc 575 log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
69b07407
YW
576 return;
577 }
578
579 if (!STR_IN_SET(NOBODY_USER_NAME, "nobody", "nfsnobody")) {
5cd33ccc 580 log_notice("Unsupported nobody user name '%s', skipping remaining tests in %s", NOBODY_USER_NAME, __func__);
57c2efa0
YW
581 return;
582 }
583
b6dc25ee
YW
584 test(m, "exec-ambientcapabilities-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
585 test(m, "exec-ambientcapabilities-merge-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
70d7aea5
IP
586}
587
63447f11
RC
588static void test_exec_privatenetwork(Manager *m) {
589 int r;
590
591 r = find_binary("ip", NULL);
592 if (r < 0) {
5cd33ccc 593 log_notice_errno(r, "Skipping %s, could not find ip binary: %m", __func__);
63447f11
RC
594 return;
595 }
596
597 test(m, "exec-privatenetwork-yes.service", 0, CLD_EXITED);
598}
599
c388dfea
RC
600static void test_exec_oomscoreadjust(Manager *m) {
601 test(m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED);
602 test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
603}
604
a6226758
RC
605static void test_exec_ioschedulingclass(Manager *m) {
606 test(m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED);
607 test(m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED);
608 test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
609 test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
610}
611
f0e018e7
YW
612static void test_exec_unsetenvironment(Manager *m) {
613 test(m, "exec-unsetenvironment.service", 0, CLD_EXITED);
42cc99d5
LP
614}
615
9672b583
LP
616static void test_exec_specifier(Manager *m) {
617 test(m, "exec-specifier.service", 0, CLD_EXITED);
8b3c4b57 618 test(m, "exec-specifier@foo-bar.service", 0, CLD_EXITED);
f0e018e7 619 test(m, "exec-specifier-interpolation.service", 0, CLD_EXITED);
9672b583
LP
620}
621
f0e018e7
YW
622static void test_exec_standardinput(Manager *m) {
623 test(m, "exec-standardinput-data.service", 0, CLD_EXITED);
624 test(m, "exec-standardinput-file.service", 0, CLD_EXITED);
666d7877
LP
625}
626
ea9cfad1
LP
627static int run_tests(UnitFileScope scope, const test_function_t *tests) {
628 const test_function_t *test = NULL;
c70cac54 629 _cleanup_(manager_freep) Manager *m = NULL;
19c0b0b9
RC
630 int r;
631
632 assert_se(tests);
633
e8112e67 634 r = manager_new(scope, MANAGER_TEST_RUN_BASIC, &m);
19c0b0b9 635 if (MANAGER_SKIP_TEST(r)) {
2179fd10 636 log_notice_errno(r, "Skipping test: manager_new: %m");
19c0b0b9
RC
637 return EXIT_TEST_SKIP;
638 }
639 assert_se(r >= 0);
640 assert_se(manager_startup(m, NULL, NULL) >= 0);
641
642 for (test = tests; test && *test; test++)
643 (*test)(m);
644
19c0b0b9
RC
645 return 0;
646}
647
281e05b6 648int main(int argc, char *argv[]) {
ac1f08b9 649 _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
ea9cfad1 650 static const test_function_t user_tests[] = {
b6dc25ee 651 test_exec_ambientcapabilities,
f0e018e7 652 test_exec_bindpaths,
f0e018e7 653 test_exec_capabilityboundingset,
4e79aeaa 654 test_exec_cpuaffinity,
f0e018e7
YW
655 test_exec_environment,
656 test_exec_environmentfile,
657 test_exec_group,
281e05b6 658 test_exec_ignoresigpipe,
f0e018e7
YW
659 test_exec_inaccessiblepaths,
660 test_exec_ioschedulingclass,
661 test_exec_oomscoreadjust,
662 test_exec_passenvironment,
663 test_exec_personality,
281e05b6 664 test_exec_privatedevices,
f0e018e7
YW
665 test_exec_privatenetwork,
666 test_exec_privatetmp,
4982dbcc 667 test_exec_protectkernelmodules,
f78b36f0 668 test_exec_readonlypaths,
cdfbd1fb 669 test_exec_readwritepaths,
f0e018e7
YW
670 test_exec_restrictnamespaces,
671 test_exec_runtimedirectory,
672 test_exec_standardinput,
673 test_exec_supplementarygroups,
281e05b6 674 test_exec_systemcallerrornumber,
f0e018e7 675 test_exec_systemcallfilter,
4cac89bd 676 test_exec_temporaryfilesystem,
27c5347c 677 test_exec_umask,
f0e018e7
YW
678 test_exec_unsetenvironment,
679 test_exec_user,
680 test_exec_workingdirectory,
281e05b6
RC
681 NULL,
682 };
ea9cfad1 683 static const test_function_t system_tests[] = {
f0e018e7 684 test_exec_dynamicuser,
9672b583 685 test_exec_specifier,
f0e018e7 686 test_exec_systemcallfilter_system,
19c0b0b9
RC
687 NULL,
688 };
281e05b6
RC
689 int r;
690
469830d1 691 log_set_max_level(LOG_DEBUG);
281e05b6
RC
692 log_parse_environment();
693 log_open();
694
2482f88d
LP
695 (void) unsetenv("USER");
696 (void) unsetenv("LOGNAME");
697
607ff5f9
DH
698 /* It is needed otherwise cgroup creation fails */
699 if (getuid() != 0) {
651d47d1 700 puts("Skipping test: not root");
607ff5f9
DH
701 return EXIT_TEST_SKIP;
702 }
703
651d47d1
ZJS
704 r = enter_cgroup_subroot();
705 if (r == -ENOMEDIUM) {
706 puts("Skipping test: cgroupfs not available");
707 return EXIT_TEST_SKIP;
708 }
8c759b33 709
ac1f08b9 710 assert_se(runtime_dir = setup_fake_runtime_dir());
cc100a5a 711 assert_se(set_unit_path(get_testdata_dir("/test-execute")) >= 0);
281e05b6 712
e1abca2e
FB
713 /* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test
714 * cases, otherwise (and if they are present in the environment),
715 * `manager_default_environment` will copy them into the default
716 * environment which is passed to each created job, which will make the
717 * tests that expect those not to be present to fail.
718 */
719 assert_se(unsetenv("VAR1") == 0);
720 assert_se(unsetenv("VAR2") == 0);
721 assert_se(unsetenv("VAR3") == 0);
722
463d0d15 723 r = run_tests(UNIT_FILE_USER, user_tests);
19c0b0b9
RC
724 if (r != 0)
725 return r;
281e05b6 726
463d0d15 727 return run_tests(UNIT_FILE_SYSTEM, system_tests);
281e05b6 728}