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