]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-namespace.c
be09f71e75233f609923c300a113fc3a4bfbb0a3
[thirdparty/systemd.git] / src / test / test-namespace.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <fcntl.h>
4 #include <sys/socket.h>
5 #include <sys/stat.h>
6
7 #include "alloc-util.h"
8 #include "fd-util.h"
9 #include "namespace.h"
10 #include "process-util.h"
11 #include "string-util.h"
12 #include "tests.h"
13 #include "user-util.h"
14 #include "virt.h"
15
16 TEST(namespace_cleanup_tmpdir) {
17 {
18 _cleanup_(namespace_cleanup_tmpdirp) char *dir;
19 assert_se(dir = strdup(RUN_SYSTEMD_EMPTY));
20 }
21
22 {
23 _cleanup_(namespace_cleanup_tmpdirp) char *dir;
24 assert_se(dir = strdup("/tmp/systemd-test-namespace.XXXXXX"));
25 assert_se(mkdtemp(dir));
26 }
27 }
28
29 static void test_tmpdir_one(const char *id, const char *A, const char *B) {
30 _cleanup_free_ char *a, *b;
31 struct stat x, y;
32 char *c, *d;
33
34 assert_se(setup_tmp_dirs(id, &a, &b) == 0);
35
36 assert_se(stat(a, &x) >= 0);
37 assert_se(stat(b, &y) >= 0);
38
39 assert_se(S_ISDIR(x.st_mode));
40 assert_se(S_ISDIR(y.st_mode));
41
42 if (!streq(a, RUN_SYSTEMD_EMPTY)) {
43 assert_se(startswith(a, A));
44 assert_se((x.st_mode & 01777) == 0700);
45 c = strjoina(a, "/tmp");
46 assert_se(stat(c, &x) >= 0);
47 assert_se(S_ISDIR(x.st_mode));
48 assert_se(FLAGS_SET(x.st_mode, 01777));
49 assert_se(rmdir(c) >= 0);
50 assert_se(rmdir(a) >= 0);
51 }
52
53 if (!streq(b, RUN_SYSTEMD_EMPTY)) {
54 assert_se(startswith(b, B));
55 assert_se((y.st_mode & 01777) == 0700);
56 d = strjoina(b, "/tmp");
57 assert_se(stat(d, &y) >= 0);
58 assert_se(S_ISDIR(y.st_mode));
59 assert_se(FLAGS_SET(y.st_mode, 01777));
60 assert_se(rmdir(d) >= 0);
61 assert_se(rmdir(b) >= 0);
62 }
63 }
64
65 TEST(tmpdir) {
66 _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *zz = NULL;
67 sd_id128_t bid;
68
69 assert_se(sd_id128_get_boot(&bid) >= 0);
70
71 x = strjoin("/tmp/systemd-private-", SD_ID128_TO_STRING(bid), "-abcd.service-");
72 y = strjoin("/var/tmp/systemd-private-", SD_ID128_TO_STRING(bid), "-abcd.service-");
73 assert_se(x && y);
74
75 test_tmpdir_one("abcd.service", x, y);
76
77 z = strjoin("/tmp/systemd-private-", SD_ID128_TO_STRING(bid), "-sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device-");
78 zz = strjoin("/var/tmp/systemd-private-", SD_ID128_TO_STRING(bid), "-sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device-");
79
80 assert_se(z && zz);
81
82 test_tmpdir_one("sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device", z, zz);
83 }
84
85 static void test_shareable_ns(unsigned long nsflag) {
86 _cleanup_close_pair_ int s[2] = { -EBADF, -EBADF };
87 pid_t pid1, pid2, pid3;
88 int r, n = 0;
89 siginfo_t si;
90
91 if (geteuid() > 0) {
92 (void) log_tests_skipped("not root");
93 return;
94 }
95
96 assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, s) >= 0);
97
98 pid1 = fork();
99 assert_se(pid1 >= 0);
100
101 if (pid1 == 0) {
102 r = setup_shareable_ns(s, nsflag);
103 assert_se(r >= 0);
104 _exit(r);
105 }
106
107 pid2 = fork();
108 assert_se(pid2 >= 0);
109
110 if (pid2 == 0) {
111 r = setup_shareable_ns(s, nsflag);
112 assert_se(r >= 0);
113 exit(r);
114 }
115
116 pid3 = fork();
117 assert_se(pid3 >= 0);
118
119 if (pid3 == 0) {
120 r = setup_shareable_ns(s, nsflag);
121 assert_se(r >= 0);
122 exit(r);
123 }
124
125 r = wait_for_terminate(pid1, &si);
126 assert_se(r >= 0);
127 assert_se(si.si_code == CLD_EXITED);
128 n += si.si_status;
129
130 r = wait_for_terminate(pid2, &si);
131 assert_se(r >= 0);
132 assert_se(si.si_code == CLD_EXITED);
133 n += si.si_status;
134
135 r = wait_for_terminate(pid3, &si);
136 assert_se(r >= 0);
137 assert_se(si.si_code == CLD_EXITED);
138 n += si.si_status;
139
140 assert_se(n == 1);
141 }
142
143 TEST(netns) {
144 test_shareable_ns(CLONE_NEWNET);
145 }
146
147 TEST(ipcns) {
148 test_shareable_ns(CLONE_NEWIPC);
149 }
150
151 TEST(protect_kernel_logs) {
152 int r;
153 pid_t pid;
154 static const NamespaceInfo ns_info = {
155 .protect_kernel_logs = true,
156 };
157
158 if (geteuid() > 0) {
159 (void) log_tests_skipped("not root");
160 return;
161 }
162
163 /* In a container we likely don't have access to /dev/kmsg */
164 if (detect_container() > 0) {
165 (void) log_tests_skipped("in container");
166 return;
167 }
168
169 pid = fork();
170 assert_se(pid >= 0);
171
172 if (pid == 0) {
173 _cleanup_close_ int fd = -EBADF;
174
175 fd = open("/dev/kmsg", O_RDONLY | O_CLOEXEC);
176 assert_se(fd > 0);
177
178 r = setup_namespace(NULL,
179 NULL,
180 NULL,
181 &ns_info,
182 NULL,
183 NULL,
184 NULL,
185 NULL,
186 NULL,
187 NULL,
188 NULL,
189 NULL, 0,
190 NULL, 0,
191 NULL, 0,
192 NULL,
193 NULL,
194 NULL,
195 NULL,
196 0,
197 NULL,
198 0,
199 NULL,
200 NULL,
201 0,
202 NULL,
203 NULL,
204 NULL,
205 0,
206 NULL,
207 NULL,
208 NULL,
209 NULL,
210 NULL,
211 NULL);
212 assert_se(r == 0);
213
214 assert_se(setresuid(UID_NOBODY, UID_NOBODY, UID_NOBODY) >= 0);
215 assert_se(open("/dev/kmsg", O_RDONLY | O_CLOEXEC) < 0);
216 assert_se(errno == EACCES);
217
218 _exit(EXIT_SUCCESS);
219 }
220
221 assert_se(wait_for_terminate_and_check("ns-kernellogs", pid, WAIT_LOG) == EXIT_SUCCESS);
222 }
223
224 static int intro(void) {
225 if (!have_namespaces())
226 return log_tests_skipped("Don't have namespace support");
227
228 return EXIT_SUCCESS;
229 }
230
231 DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);