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