1
2
3#define _GNU_SOURCE
4#include <errno.h>
5#include <fcntl.h>
6#include <linux/netlink.h>
7#include <signal.h>
8#include <stdbool.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/prctl.h>
13#include <sys/socket.h>
14#include <sched.h>
15#include <sys/eventfd.h>
16#include <sys/stat.h>
17#include <sys/syscall.h>
18#include <sys/types.h>
19#include <sys/wait.h>
20#include <unistd.h>
21
22#include "../kselftest_harness.h"
23
24#define __DEV_FULL "/sys/devices/virtual/mem/full/uevent"
25#define __UEVENT_BUFFER_SIZE (2048 * 2)
26#define __UEVENT_HEADER "add@/devices/virtual/mem/full"
27#define __UEVENT_HEADER_LEN sizeof("add@/devices/virtual/mem/full")
28#define __UEVENT_LISTEN_ALL -1
29
30ssize_t read_nointr(int fd, void *buf, size_t count)
31{
32 ssize_t ret;
33
34again:
35 ret = read(fd, buf, count);
36 if (ret < 0 && errno == EINTR)
37 goto again;
38
39 return ret;
40}
41
42ssize_t write_nointr(int fd, const void *buf, size_t count)
43{
44 ssize_t ret;
45
46again:
47 ret = write(fd, buf, count);
48 if (ret < 0 && errno == EINTR)
49 goto again;
50
51 return ret;
52}
53
54int wait_for_pid(pid_t pid)
55{
56 int status, ret;
57
58again:
59 ret = waitpid(pid, &status, 0);
60 if (ret == -1) {
61 if (errno == EINTR)
62 goto again;
63
64 return -1;
65 }
66
67 if (ret != pid)
68 goto again;
69
70 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
71 return -1;
72
73 return 0;
74}
75
76static int uevent_listener(unsigned long post_flags, bool expect_uevent,
77 int sync_fd)
78{
79 int sk_fd, ret;
80 socklen_t sk_addr_len;
81 int fret = -1, rcv_buf_sz = __UEVENT_BUFFER_SIZE;
82 uint64_t sync_add = 1;
83 struct sockaddr_nl sk_addr = { 0 }, rcv_addr = { 0 };
84 char buf[__UEVENT_BUFFER_SIZE] = { 0 };
85 struct iovec iov = { buf, __UEVENT_BUFFER_SIZE };
86 char control[CMSG_SPACE(sizeof(struct ucred))];
87 struct msghdr hdr = {
88 &rcv_addr, sizeof(rcv_addr), &iov, 1,
89 control, sizeof(control), 0,
90 };
91
92 sk_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC,
93 NETLINK_KOBJECT_UEVENT);
94 if (sk_fd < 0) {
95 fprintf(stderr, "%s - Failed to open uevent socket\n", strerror(errno));
96 return -1;
97 }
98
99 ret = setsockopt(sk_fd, SOL_SOCKET, SO_RCVBUF, &rcv_buf_sz,
100 sizeof(rcv_buf_sz));
101 if (ret < 0) {
102 fprintf(stderr, "%s - Failed to set socket options\n", strerror(errno));
103 goto on_error;
104 }
105
106 sk_addr.nl_family = AF_NETLINK;
107 sk_addr.nl_groups = __UEVENT_LISTEN_ALL;
108
109 sk_addr_len = sizeof(sk_addr);
110 ret = bind(sk_fd, (struct sockaddr *)&sk_addr, sk_addr_len);
111 if (ret < 0) {
112 fprintf(stderr, "%s - Failed to bind socket\n", strerror(errno));
113 goto on_error;
114 }
115
116 ret = getsockname(sk_fd, (struct sockaddr *)&sk_addr, &sk_addr_len);
117 if (ret < 0) {
118 fprintf(stderr, "%s - Failed to retrieve socket name\n", strerror(errno));
119 goto on_error;
120 }
121
122 if ((size_t)sk_addr_len != sizeof(sk_addr)) {
123 fprintf(stderr, "Invalid socket address size\n");
124 goto on_error;
125 }
126
127 if (post_flags & CLONE_NEWUSER) {
128 ret = unshare(CLONE_NEWUSER);
129 if (ret < 0) {
130 fprintf(stderr,
131 "%s - Failed to unshare user namespace\n",
132 strerror(errno));
133 goto on_error;
134 }
135 }
136
137 if (post_flags & CLONE_NEWNET) {
138 ret = unshare(CLONE_NEWNET);
139 if (ret < 0) {
140 fprintf(stderr,
141 "%s - Failed to unshare network namespace\n",
142 strerror(errno));
143 goto on_error;
144 }
145 }
146
147 ret = write_nointr(sync_fd, &sync_add, sizeof(sync_add));
148 close(sync_fd);
149 if (ret != sizeof(sync_add)) {
150 fprintf(stderr, "Failed to synchronize with parent process\n");
151 goto on_error;
152 }
153
154 fret = 0;
155 for (;;) {
156 ssize_t r;
157
158 r = recvmsg(sk_fd, &hdr, 0);
159 if (r <= 0) {
160 fprintf(stderr, "%s - Failed to receive uevent\n", strerror(errno));
161 ret = -1;
162 break;
163 }
164
165
166 if (memcmp(buf, "libudev", 8) == 0)
167 continue;
168
169
170 if (memcmp(buf, __UEVENT_HEADER, __UEVENT_HEADER_LEN) != 0)
171 continue;
172
173 if (!expect_uevent) {
174 fprintf(stderr, "Received unexpected uevent:\n");
175 ret = -1;
176 }
177
178 if (TH_LOG_ENABLED) {
179
180 (void)write_nointr(STDERR_FILENO, buf, r);
181 (void)write_nointr(STDERR_FILENO, "\n", 1);
182 }
183
184 break;
185 }
186
187on_error:
188 close(sk_fd);
189
190 return fret;
191}
192
193int trigger_uevent(unsigned int times)
194{
195 int fd, ret;
196 unsigned int i;
197
198 fd = open(__DEV_FULL, O_RDWR | O_CLOEXEC);
199 if (fd < 0) {
200 if (errno != ENOENT)
201 return -EINVAL;
202
203 return -1;
204 }
205
206 for (i = 0; i < times; i++) {
207 ret = write_nointr(fd, "add\n", sizeof("add\n") - 1);
208 if (ret < 0) {
209 fprintf(stderr, "Failed to trigger uevent\n");
210 break;
211 }
212 }
213 close(fd);
214
215 return ret;
216}
217
218int set_death_signal(void)
219{
220 int ret;
221 pid_t ppid;
222
223 ret = prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
224
225
226 ppid = getppid();
227 if (ppid == 1) {
228 pid_t self;
229
230 self = getpid();
231 ret = kill(self, SIGKILL);
232 }
233
234 if (ret < 0)
235 return -1;
236
237 return 0;
238}
239
240static int do_test(unsigned long pre_flags, unsigned long post_flags,
241 bool expect_uevent, int sync_fd)
242{
243 int ret;
244 uint64_t wait_val;
245 pid_t pid;
246 sigset_t mask;
247 sigset_t orig_mask;
248 struct timespec timeout;
249
250 sigemptyset(&mask);
251 sigaddset(&mask, SIGCHLD);
252
253 ret = sigprocmask(SIG_BLOCK, &mask, &orig_mask);
254 if (ret < 0) {
255 fprintf(stderr, "%s- Failed to block SIGCHLD\n", strerror(errno));
256 return -1;
257 }
258
259 pid = fork();
260 if (pid < 0) {
261 fprintf(stderr, "%s - Failed to fork() new process\n", strerror(errno));
262 return -1;
263 }
264
265 if (pid == 0) {
266
267 ret = set_death_signal();
268 if (ret < 0) {
269 fprintf(stderr, "Failed to set PR_SET_PDEATHSIG to SIGKILL\n");
270 _exit(EXIT_FAILURE);
271 }
272
273 if (pre_flags & CLONE_NEWUSER) {
274 ret = unshare(CLONE_NEWUSER);
275 if (ret < 0) {
276 fprintf(stderr,
277 "%s - Failed to unshare user namespace\n",
278 strerror(errno));
279 _exit(EXIT_FAILURE);
280 }
281 }
282
283 if (pre_flags & CLONE_NEWNET) {
284 ret = unshare(CLONE_NEWNET);
285 if (ret < 0) {
286 fprintf(stderr,
287 "%s - Failed to unshare network namespace\n",
288 strerror(errno));
289 _exit(EXIT_FAILURE);
290 }
291 }
292
293 if (uevent_listener(post_flags, expect_uevent, sync_fd) < 0)
294 _exit(EXIT_FAILURE);
295
296 _exit(EXIT_SUCCESS);
297 }
298
299 ret = read_nointr(sync_fd, &wait_val, sizeof(wait_val));
300 if (ret != sizeof(wait_val)) {
301 fprintf(stderr, "Failed to synchronize with child process\n");
302 _exit(EXIT_FAILURE);
303 }
304
305
306
307
308 ret = trigger_uevent(10);
309 if (ret < 0)
310 fprintf(stderr, "Failed triggering uevents\n");
311
312
313
314
315
316 timeout.tv_sec = 2;
317 timeout.tv_nsec = 0;
318
319again:
320 ret = sigtimedwait(&mask, NULL, &timeout);
321 if (ret < 0) {
322 if (errno == EINTR)
323 goto again;
324
325 if (!expect_uevent)
326 ret = kill(pid, SIGTERM);
327 else
328 ret = kill(pid, SIGUSR1);
329 if (ret < 0)
330 return -1;
331 }
332
333 ret = wait_for_pid(pid);
334 if (ret < 0)
335 return -1;
336
337 return ret;
338}
339
340static void signal_handler(int sig)
341{
342 if (sig == SIGTERM)
343 _exit(EXIT_SUCCESS);
344
345 _exit(EXIT_FAILURE);
346}
347
348TEST(uevent_filtering)
349{
350 int ret, sync_fd;
351 struct sigaction act;
352
353 if (geteuid()) {
354 TH_LOG("Uevent filtering tests require root privileges. Skipping test");
355 _exit(KSFT_SKIP);
356 }
357
358 ret = access(__DEV_FULL, F_OK);
359 EXPECT_EQ(0, ret) {
360 if (errno == ENOENT) {
361 TH_LOG(__DEV_FULL " does not exist. Skipping test");
362 _exit(KSFT_SKIP);
363 }
364
365 _exit(KSFT_FAIL);
366 }
367
368 act.sa_handler = signal_handler;
369 act.sa_flags = 0;
370 sigemptyset(&act.sa_mask);
371
372 ret = sigaction(SIGTERM, &act, NULL);
373 ASSERT_EQ(0, ret);
374
375 sync_fd = eventfd(0, EFD_CLOEXEC);
376 ASSERT_GE(sync_fd, 0);
377
378
379
380
381
382
383
384
385
386
387 ret = do_test(0, 0, true, sync_fd);
388 ASSERT_EQ(0, ret) {
389 goto do_cleanup;
390 }
391
392
393
394
395
396
397
398
399
400
401 ret = do_test(CLONE_NEWNET, 0, true, sync_fd);
402 ASSERT_EQ(0, ret) {
403 goto do_cleanup;
404 }
405
406
407
408
409
410
411
412
413
414
415
416 ret = do_test(CLONE_NEWUSER, 0, true, sync_fd);
417 ASSERT_EQ(0, ret) {
418 goto do_cleanup;
419 }
420
421
422
423
424
425
426
427
428
429
430 ret = do_test(CLONE_NEWUSER | CLONE_NEWNET, 0, false, sync_fd);
431 ASSERT_EQ(0, ret) {
432 goto do_cleanup;
433 }
434
435
436
437
438
439
440
441
442
443
444
445 ret = do_test(0, CLONE_NEWNET, true, sync_fd);
446 ASSERT_EQ(0, ret) {
447 goto do_cleanup;
448 }
449
450
451
452
453
454
455
456
457
458
459
460 ret = do_test(0, CLONE_NEWUSER, true, sync_fd);
461 ASSERT_EQ(0, ret) {
462 goto do_cleanup;
463 }
464
465
466
467
468
469
470
471
472
473
474
475
476 ret = do_test(0, CLONE_NEWUSER | CLONE_NEWNET, true, sync_fd);
477 ASSERT_EQ(0, ret) {
478 goto do_cleanup;
479 }
480
481do_cleanup:
482 close(sync_fd);
483}
484
485TEST_HARNESS_MAIN
486