1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Ronny Chevalier
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.
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.
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/>.
24 #include <sys/prctl.h>
25 #include <sys/types.h>
27 #include "errno-list.h"
33 #include "path-util.h"
36 #include "seccomp-util.h"
38 #include "stat-util.h"
39 #include "test-helper.h"
45 typedef void (*test_function_t
)(Manager
*m
);
47 static void check(Manager
*m
, Unit
*unit
, int status_expected
, int code_expected
) {
48 Service
*service
= NULL
;
50 usec_t timeout
= 2 * USEC_PER_MINUTE
;
55 service
= SERVICE(unit
);
56 printf("%s\n", unit
->id
);
57 exec_context_dump(&service
->exec_context
, stdout
, "\t");
58 ts
= now(CLOCK_MONOTONIC
);
59 while (!IN_SET(service
->state
, SERVICE_DEAD
, SERVICE_FAILED
)) {
63 r
= sd_event_run(m
->event
, 100 * USEC_PER_MSEC
);
66 n
= now(CLOCK_MONOTONIC
);
67 if (ts
+ timeout
< n
) {
68 log_error("Test timeout when testing %s", unit
->id
);
72 exec_status_dump(&service
->main_exec_status
, stdout
, "\t");
73 assert_se(service
->main_exec_status
.status
== status_expected
);
74 assert_se(service
->main_exec_status
.code
== code_expected
);
77 static bool is_inaccessible_available(void) {
81 "/run/systemd/inaccessible/reg",
82 "/run/systemd/inaccessible/dir",
83 "/run/systemd/inaccessible/chr",
84 "/run/systemd/inaccessible/blk",
85 "/run/systemd/inaccessible/fifo",
86 "/run/systemd/inaccessible/sock"
88 if (access(p
, F_OK
) < 0)
95 static void test(Manager
*m
, const char *unit_name
, int status_expected
, int code_expected
) {
100 assert_se(manager_load_unit(m
, unit_name
, NULL
, NULL
, &unit
) >= 0);
101 assert_se(UNIT_VTABLE(unit
)->start(unit
) >= 0);
102 check(m
, unit
, status_expected
, code_expected
);
105 static void test_exec_bind_paths(Manager
*m
) {
106 assert_se(mkdir_p("/tmp/test-exec_bind_paths", 0755) >= 0);
107 assert_se(mkdir_p("/tmp/test-exec_bind_readonly_paths", 0755) >= 0);
109 test(m
, "exec-bind-paths.service", 0, CLD_EXITED
);
111 (void) rm_rf("/tmp/test-exec_bind_paths", REMOVE_ROOT
|REMOVE_PHYSICAL
);
112 (void) rm_rf("/tmp/test-exec_bind_readonly_paths", REMOVE_ROOT
|REMOVE_PHYSICAL
);
115 static void test_exec_workingdirectory(Manager
*m
) {
116 assert_se(mkdir_p("/tmp/test-exec_workingdirectory", 0755) >= 0);
118 test(m
, "exec-workingdirectory.service", 0, CLD_EXITED
);
120 (void) rm_rf("/tmp/test-exec_workingdirectory", REMOVE_ROOT
|REMOVE_PHYSICAL
);
123 static void test_exec_personality(Manager
*m
) {
124 #if defined(__x86_64__)
125 test(m
, "exec-personality-x86-64.service", 0, CLD_EXITED
);
127 #elif defined(__s390__)
128 test(m
, "exec-personality-s390.service", 0, CLD_EXITED
);
130 #elif defined(__powerpc64__)
131 # if __BYTE_ORDER == __BIG_ENDIAN
132 test(m
, "exec-personality-ppc64.service", 0, CLD_EXITED
);
134 test(m
, "exec-personality-ppc64le.service", 0, CLD_EXITED
);
137 #elif defined(__aarch64__)
138 test(m
, "exec-personality-aarch64.service", 0, CLD_EXITED
);
140 #elif defined(__i386__)
141 test(m
, "exec-personality-x86.service", 0, CLD_EXITED
);
145 static void test_exec_ignoresigpipe(Manager
*m
) {
146 test(m
, "exec-ignoresigpipe-yes.service", 0, CLD_EXITED
);
147 test(m
, "exec-ignoresigpipe-no.service", SIGPIPE
, CLD_KILLED
);
150 static void test_exec_privatetmp(Manager
*m
) {
151 assert_se(touch("/tmp/test-exec_privatetmp") >= 0);
153 test(m
, "exec-privatetmp-yes.service", 0, CLD_EXITED
);
154 test(m
, "exec-privatetmp-no.service", 0, CLD_EXITED
);
156 unlink("/tmp/test-exec_privatetmp");
159 static void test_exec_privatedevices(Manager
*m
) {
160 if (detect_container() > 0) {
161 log_notice("testing in container, skipping %s", __func__
);
164 if (!is_inaccessible_available()) {
165 log_notice("testing without inaccessible, skipping %s", __func__
);
169 test(m
, "exec-privatedevices-yes.service", 0, CLD_EXITED
);
170 test(m
, "exec-privatedevices-no.service", 0, CLD_EXITED
);
173 static void test_exec_privatedevices_capabilities(Manager
*m
) {
176 if (detect_container() > 0) {
177 log_notice("testing in container, skipping %s", __func__
);
180 if (!is_inaccessible_available()) {
181 log_notice("testing without inaccessible, skipping %s", __func__
);
185 /* We use capsh to test if the capabilities are
186 * properly set, so be sure that it exists */
187 r
= find_binary("capsh", NULL
);
189 log_error_errno(r
, "Skipping %s, could not find capsh binary: %m", __func__
);
193 test(m
, "exec-privatedevices-yes-capability-mknod.service", 0, CLD_EXITED
);
194 test(m
, "exec-privatedevices-no-capability-mknod.service", 0, CLD_EXITED
);
195 test(m
, "exec-privatedevices-yes-capability-sys-rawio.service", 0, CLD_EXITED
);
196 test(m
, "exec-privatedevices-no-capability-sys-rawio.service", 0, CLD_EXITED
);
199 static void test_exec_protectkernelmodules(Manager
*m
) {
202 if (detect_container() > 0) {
203 log_notice("testing in container, skipping %s", __func__
);
206 if (!is_inaccessible_available()) {
207 log_notice("testing without inaccessible, skipping %s", __func__
);
211 r
= find_binary("capsh", NULL
);
213 log_error_errno(r
, "Skipping %s, could not find capsh binary: %m", __func__
);
218 test(m
, "exec-protectkernelmodules-no-capabilities.service", 0, CLD_EXITED
);
219 test(m
, "exec-protectkernelmodules-yes-capabilities.service", 0, CLD_EXITED
);
220 test(m
, "exec-protectkernelmodules-yes-mount-propagation.service", 0, CLD_EXITED
);
223 static void test_exec_readonlypaths(Manager
*m
) {
225 if (path_is_read_only_fs("/var") > 0)
228 test(m
, "exec-readonlypaths.service", 0, CLD_EXITED
);
229 test(m
, "exec-readonlypaths-mount-propagation.service", 0, CLD_EXITED
);
230 test(m
, "exec-readonlypaths-with-bindpaths.service", 0, CLD_EXITED
);
233 static void test_exec_readwritepaths(Manager
*m
) {
235 if (path_is_read_only_fs("/") > 0)
238 test(m
, "exec-readwritepaths-mount-propagation.service", 0, CLD_EXITED
);
241 static void test_exec_inaccessiblepaths(Manager
*m
) {
243 if (path_is_read_only_fs("/") > 0)
246 test(m
, "exec-inaccessiblepaths-mount-propagation.service", 0, CLD_EXITED
);
249 static void test_exec_inaccessiblepaths_proc(Manager
*m
) {
250 if (!is_inaccessible_available()) {
251 log_notice("testing without inaccessible, skipping %s", __func__
);
255 test(m
, "exec-inaccessiblepaths-proc.service", 0, CLD_EXITED
);
258 static void test_exec_systemcallfilter(Manager
*m
) {
260 if (!is_seccomp_available())
262 test(m
, "exec-systemcallfilter-not-failing.service", 0, CLD_EXITED
);
263 test(m
, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED
);
264 test(m
, "exec-systemcallfilter-failing.service", SIGSYS
, CLD_KILLED
);
265 test(m
, "exec-systemcallfilter-failing2.service", SIGSYS
, CLD_KILLED
);
266 test(m
, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED
);
267 test(m
, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED
);
272 static void test_exec_systemcallerrornumber(Manager
*m
) {
274 if (!is_seccomp_available())
276 test(m
, "exec-systemcallerrornumber-name.service", errno_from_name("EACCES"), CLD_EXITED
);
277 test(m
, "exec-systemcallerrornumber-number.service", 255, CLD_EXITED
);
281 static void test_exec_restrict_namespaces(Manager
*m
) {
283 if (!is_seccomp_available())
286 test(m
, "exec-restrict-namespaces-no.service", 0, CLD_EXITED
);
287 test(m
, "exec-restrict-namespaces-yes.service", 1, CLD_EXITED
);
288 test(m
, "exec-restrict-namespaces-mnt.service", 0, CLD_EXITED
);
289 test(m
, "exec-restrict-namespaces-mnt-blacklist.service", 1, CLD_EXITED
);
293 static void test_exec_systemcall_system_mode_with_user(Manager
*m
) {
295 if (!is_seccomp_available())
297 if (getpwnam("nobody"))
298 test(m
, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED
);
299 else if (getpwnam("nfsnobody"))
300 test(m
, "exec-systemcallfilter-system-user-nfsnobody.service", 0, CLD_EXITED
);
302 log_error_errno(errno
, "Skipping %s, could not find nobody/nfsnobody user: %m", __func__
);
306 static void test_exec_user(Manager
*m
) {
307 if (getpwnam("nobody"))
308 test(m
, "exec-user.service", 0, CLD_EXITED
);
309 else if (getpwnam("nfsnobody"))
310 test(m
, "exec-user-nfsnobody.service", 0, CLD_EXITED
);
312 log_error_errno(errno
, "Skipping %s, could not find nobody/nfsnobody user: %m", __func__
);
315 static void test_exec_group(Manager
*m
) {
316 if (getgrnam("nobody"))
317 test(m
, "exec-group.service", 0, CLD_EXITED
);
318 else if (getgrnam("nfsnobody"))
319 test(m
, "exec-group-nfsnobody.service", 0, CLD_EXITED
);
321 log_error_errno(errno
, "Skipping %s, could not find nobody/nfsnobody group: %m", __func__
);
324 static void test_exec_supplementary_groups(Manager
*m
) {
325 test(m
, "exec-supplementarygroups.service", 0, CLD_EXITED
);
326 test(m
, "exec-supplementarygroups-single-group.service", 0, CLD_EXITED
);
327 test(m
, "exec-supplementarygroups-single-group-user.service", 0, CLD_EXITED
);
328 test(m
, "exec-supplementarygroups-multiple-groups-default-group-user.service", 0, CLD_EXITED
);
329 test(m
, "exec-supplementarygroups-multiple-groups-withgid.service", 0, CLD_EXITED
);
330 test(m
, "exec-supplementarygroups-multiple-groups-withuid.service", 0, CLD_EXITED
);
333 static void test_exec_dynamic_user(Manager
*m
) {
334 test(m
, "exec-dynamicuser-fixeduser.service", 0, CLD_EXITED
);
335 test(m
, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", 0, CLD_EXITED
);
336 test(m
, "exec-dynamicuser-supplementarygroups.service", 0, CLD_EXITED
);
337 test(m
, "exec-dynamicuser-state-dir.service", 0, CLD_EXITED
);
340 static void test_exec_environment(Manager
*m
) {
341 test(m
, "exec-environment.service", 0, CLD_EXITED
);
342 test(m
, "exec-environment-multiple.service", 0, CLD_EXITED
);
343 test(m
, "exec-environment-empty.service", 0, CLD_EXITED
);
346 static void test_exec_environmentfile(Manager
*m
) {
347 static const char e
[] =
348 "VAR1='word1 word2'\n"
354 "line without an equal\n"
355 "VAR3='$word 5 6'\n";
358 r
= write_string_file("/tmp/test-exec_environmentfile.conf", e
, WRITE_STRING_FILE_CREATE
);
361 test(m
, "exec-environmentfile.service", 0, CLD_EXITED
);
363 unlink("/tmp/test-exec_environmentfile.conf");
366 static void test_exec_passenvironment(Manager
*m
) {
367 /* test-execute runs under MANAGER_USER which, by default, forwards all
368 * variables present in the environment, but only those that are
369 * present _at the time it is created_!
371 * So these PassEnvironment checks are still expected to work, since we
372 * are ensuring the variables are not present at manager creation (they
373 * are unset explicitly in main) and are only set here.
375 * This is still a good approximation of how a test for MANAGER_SYSTEM
378 assert_se(setenv("VAR1", "word1 word2", 1) == 0);
379 assert_se(setenv("VAR2", "word3", 1) == 0);
380 assert_se(setenv("VAR3", "$word 5 6", 1) == 0);
381 test(m
, "exec-passenvironment.service", 0, CLD_EXITED
);
382 test(m
, "exec-passenvironment-repeated.service", 0, CLD_EXITED
);
383 test(m
, "exec-passenvironment-empty.service", 0, CLD_EXITED
);
384 assert_se(unsetenv("VAR1") == 0);
385 assert_se(unsetenv("VAR2") == 0);
386 assert_se(unsetenv("VAR3") == 0);
387 test(m
, "exec-passenvironment-absent.service", 0, CLD_EXITED
);
390 static void test_exec_umask(Manager
*m
) {
391 test(m
, "exec-umask-default.service", 0, CLD_EXITED
);
392 test(m
, "exec-umask-0177.service", 0, CLD_EXITED
);
395 static void test_exec_runtimedirectory(Manager
*m
) {
396 test(m
, "exec-runtimedirectory.service", 0, CLD_EXITED
);
397 test(m
, "exec-runtimedirectory-mode.service", 0, CLD_EXITED
);
398 if (getgrnam("nobody"))
399 test(m
, "exec-runtimedirectory-owner.service", 0, CLD_EXITED
);
400 else if (getgrnam("nfsnobody"))
401 test(m
, "exec-runtimedirectory-owner-nfsnobody.service", 0, CLD_EXITED
);
403 log_error_errno(errno
, "Skipping %s, could not find nobody/nfsnobody group: %m", __func__
);
406 static void test_exec_capabilityboundingset(Manager
*m
) {
409 r
= find_binary("capsh", NULL
);
411 log_error_errno(r
, "Skipping %s, could not find capsh binary: %m", __func__
);
415 test(m
, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED
);
416 test(m
, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED
);
417 test(m
, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED
);
418 test(m
, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED
);
421 static void test_exec_capabilityambientset(Manager
*m
) {
424 /* Check if the kernel has support for ambient capabilities. Run
425 * the tests only if that's the case. Clearing all ambient
426 * capabilities is fine, since we are expecting them to be unset
427 * in the first place for the tests. */
428 r
= prctl(PR_CAP_AMBIENT
, PR_CAP_AMBIENT_CLEAR_ALL
, 0, 0, 0);
429 if (r
>= 0 || errno
!= EINVAL
) {
430 if (getpwnam("nobody")) {
431 test(m
, "exec-capabilityambientset.service", 0, CLD_EXITED
);
432 test(m
, "exec-capabilityambientset-merge.service", 0, CLD_EXITED
);
433 } else if (getpwnam("nfsnobody")) {
434 test(m
, "exec-capabilityambientset-nfsnobody.service", 0, CLD_EXITED
);
435 test(m
, "exec-capabilityambientset-merge-nfsnobody.service", 0, CLD_EXITED
);
437 log_error_errno(errno
, "Skipping %s, could not find nobody/nfsnobody user: %m", __func__
);
439 log_error_errno(errno
, "Skipping %s, the kernel does not support ambient capabilities: %m", __func__
);
442 static void test_exec_privatenetwork(Manager
*m
) {
445 r
= find_binary("ip", NULL
);
447 log_error_errno(r
, "Skipping %s, could not find ip binary: %m", __func__
);
451 test(m
, "exec-privatenetwork-yes.service", 0, CLD_EXITED
);
454 static void test_exec_oomscoreadjust(Manager
*m
) {
455 test(m
, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED
);
456 test(m
, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED
);
459 static void test_exec_ioschedulingclass(Manager
*m
) {
460 test(m
, "exec-ioschedulingclass-none.service", 0, CLD_EXITED
);
461 test(m
, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED
);
462 test(m
, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED
);
463 test(m
, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED
);
466 static void test_exec_spec_interpolation(Manager
*m
) {
467 test(m
, "exec-spec-interpolation.service", 0, CLD_EXITED
);
470 static void test_exec_read_only_path_suceed(Manager
*m
) {
471 test(m
, "exec-read-only-path-succeed.service", 0, CLD_EXITED
);
474 static void test_exec_unset_environment(Manager
*m
) {
475 test(m
, "exec-unset-environment.service", 0, CLD_EXITED
);
478 static void test_exec_specifier(Manager
*m
) {
479 test(m
, "exec-specifier.service", 0, CLD_EXITED
);
480 test(m
, "exec-specifier@foo-bar.service", 0, CLD_EXITED
);
483 static void test_exec_stdin_data(Manager
*m
) {
484 test(m
, "exec-stdin-data.service", 0, CLD_EXITED
);
487 static void test_exec_stdio_file(Manager
*m
) {
488 test(m
, "exec-stdio-file.service", 0, CLD_EXITED
);
491 static int run_tests(UnitFileScope scope
, const test_function_t
*tests
) {
492 const test_function_t
*test
= NULL
;
498 r
= manager_new(scope
, MANAGER_TEST_RUN_MINIMAL
, &m
);
499 if (MANAGER_SKIP_TEST(r
)) {
500 log_notice_errno(r
, "Skipping test: manager_new: %m");
501 return EXIT_TEST_SKIP
;
504 assert_se(manager_startup(m
, NULL
, NULL
) >= 0);
506 for (test
= tests
; test
&& *test
; test
++)
514 int main(int argc
, char *argv
[]) {
515 static const test_function_t user_tests
[] = {
516 test_exec_bind_paths
,
517 test_exec_workingdirectory
,
518 test_exec_personality
,
519 test_exec_ignoresigpipe
,
520 test_exec_privatetmp
,
521 test_exec_privatedevices
,
522 test_exec_privatedevices_capabilities
,
523 test_exec_protectkernelmodules
,
524 test_exec_readonlypaths
,
525 test_exec_readwritepaths
,
526 test_exec_inaccessiblepaths
,
527 test_exec_inaccessiblepaths_proc
,
528 test_exec_privatenetwork
,
529 test_exec_systemcallfilter
,
530 test_exec_systemcallerrornumber
,
531 test_exec_restrict_namespaces
,
534 test_exec_supplementary_groups
,
535 test_exec_environment
,
536 test_exec_environmentfile
,
537 test_exec_passenvironment
,
539 test_exec_runtimedirectory
,
540 test_exec_capabilityboundingset
,
541 test_exec_capabilityambientset
,
542 test_exec_oomscoreadjust
,
543 test_exec_ioschedulingclass
,
544 test_exec_spec_interpolation
,
545 test_exec_read_only_path_suceed
,
546 test_exec_unset_environment
,
547 test_exec_stdin_data
,
548 test_exec_stdio_file
,
551 static const test_function_t system_tests
[] = {
552 test_exec_systemcall_system_mode_with_user
,
553 test_exec_dynamic_user
,
559 log_set_max_level(LOG_DEBUG
);
560 log_parse_environment();
563 /* It is needed otherwise cgroup creation fails */
565 puts("Skipping test: not root");
566 return EXIT_TEST_SKIP
;
569 r
= enter_cgroup_subroot();
570 if (r
== -ENOMEDIUM
) {
571 puts("Skipping test: cgroupfs not available");
572 return EXIT_TEST_SKIP
;
575 assert_se(setenv("XDG_RUNTIME_DIR", "/tmp/", 1) == 0);
576 assert_se(set_unit_path(get_testdata_dir("/test-execute")) >= 0);
578 /* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test
579 * cases, otherwise (and if they are present in the environment),
580 * `manager_default_environment` will copy them into the default
581 * environment which is passed to each created job, which will make the
582 * tests that expect those not to be present to fail.
584 assert_se(unsetenv("VAR1") == 0);
585 assert_se(unsetenv("VAR2") == 0);
586 assert_se(unsetenv("VAR3") == 0);
588 r
= run_tests(UNIT_FILE_USER
, user_tests
);
592 return run_tests(UNIT_FILE_SYSTEM
, system_tests
);