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