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