GNU Linux-libre 4.19.286-gnu1
[releases.git] / tools / testing / selftests / uevent / uevent_filtering.c
1 // SPDX-License-Identifier: GPL-2.0
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
31 ssize_t read_nointr(int fd, void *buf, size_t count)
32 {
33         ssize_t ret;
34
35 again:
36         ret = read(fd, buf, count);
37         if (ret < 0 && errno == EINTR)
38                 goto again;
39
40         return ret;
41 }
42
43 ssize_t write_nointr(int fd, const void *buf, size_t count)
44 {
45         ssize_t ret;
46
47 again:
48         ret = write(fd, buf, count);
49         if (ret < 0 && errno == EINTR)
50                 goto again;
51
52         return ret;
53 }
54
55 int wait_for_pid(pid_t pid)
56 {
57         int status, ret;
58
59 again:
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
77 static 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                 /* ignore libudev messages */
167                 if (memcmp(buf, "libudev", 8) == 0)
168                         continue;
169
170                 /* ignore uevents we didn't trigger */
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                         /* If logging is enabled dump the received uevent. */
181                         (void)write_nointr(STDERR_FILENO, buf, r);
182                         (void)write_nointr(STDERR_FILENO, "\n", 1);
183                 }
184
185                 break;
186         }
187
188 on_error:
189         close(sk_fd);
190
191         return fret;
192 }
193
194 int 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
219 int 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         /* Check whether we have been orphaned. */
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
241 static 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                 /* Make sure that we go away when our parent dies. */
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         /* Trigger 10 uevents to account for the case where the kernel might
307          * drop some.
308          */
309         ret = trigger_uevent(10);
310         if (ret < 0)
311                 fprintf(stderr, "Failed triggering uevents\n");
312
313         /* Wait for 2 seconds before considering this failed. This should be
314          * plenty of time for the kernel to deliver the uevent even under heavy
315          * load.
316          */
317         timeout.tv_sec = 2;
318         timeout.tv_nsec = 0;
319
320 again:
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); /* success */
328                 else
329                         ret = kill(pid, SIGUSR1); /* error */
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
341 static void signal_handler(int sig)
342 {
343         if (sig == SIGTERM)
344                 _exit(EXIT_SUCCESS);
345
346         _exit(EXIT_FAILURE);
347 }
348
349 TEST(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          * Setup:
381          * - Open uevent listening socket in initial network namespace owned by
382          *   initial user namespace.
383          * - Trigger uevent in initial network namespace owned by initial user
384          *   namespace.
385          * Expected Result:
386          * - uevent listening socket receives uevent
387          */
388         ret = do_test(0, 0, true, sync_fd);
389         ASSERT_EQ(0, ret) {
390                 goto do_cleanup;
391         }
392
393         /*
394          * Setup:
395          * - Open uevent listening socket in non-initial network namespace
396          *   owned by initial user namespace.
397          * - Trigger uevent in initial network namespace owned by initial user
398          *   namespace.
399          * Expected Result:
400          * - uevent listening socket receives uevent
401          */
402         ret = do_test(CLONE_NEWNET, 0, true, sync_fd);
403         ASSERT_EQ(0, ret) {
404                 goto do_cleanup;
405         }
406
407         /*
408          * Setup:
409          * - unshare user namespace
410          * - Open uevent listening socket in initial network namespace
411          *   owned by initial user namespace.
412          * - Trigger uevent in initial network namespace owned by initial user
413          *   namespace.
414          * Expected Result:
415          * - uevent listening socket receives uevent
416          */
417         ret = do_test(CLONE_NEWUSER, 0, true, sync_fd);
418         ASSERT_EQ(0, ret) {
419                 goto do_cleanup;
420         }
421
422         /*
423          * Setup:
424          * - Open uevent listening socket in non-initial network namespace
425          *   owned by non-initial user namespace.
426          * - Trigger uevent in initial network namespace owned by initial user
427          *   namespace.
428          * Expected Result:
429          * - uevent listening socket receives no uevent
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          * Setup:
438          * - Open uevent listening socket in initial network namespace
439          *   owned by initial user namespace.
440          * - unshare network namespace
441          * - Trigger uevent in initial network namespace owned by initial user
442          *   namespace.
443          * Expected Result:
444          * - uevent listening socket receives uevent
445          */
446         ret = do_test(0, CLONE_NEWNET, true, sync_fd);
447         ASSERT_EQ(0, ret) {
448                 goto do_cleanup;
449         }
450
451         /*
452          * Setup:
453          * - Open uevent listening socket in initial network namespace
454          *   owned by initial user namespace.
455          * - unshare user namespace
456          * - Trigger uevent in initial network namespace owned by initial user
457          *   namespace.
458          * Expected Result:
459          * - uevent listening socket receives uevent
460          */
461         ret = do_test(0, CLONE_NEWUSER, true, sync_fd);
462         ASSERT_EQ(0, ret) {
463                 goto do_cleanup;
464         }
465
466         /*
467          * Setup:
468          * - Open uevent listening socket in initial network namespace
469          *   owned by initial user namespace.
470          * - unshare user namespace
471          * - unshare network namespace
472          * - Trigger uevent in initial network namespace owned by initial user
473          *   namespace.
474          * Expected Result:
475          * - uevent listening socket receives uevent
476          */
477         ret = do_test(0, CLONE_NEWUSER | CLONE_NEWNET, true, sync_fd);
478         ASSERT_EQ(0, ret) {
479                 goto do_cleanup;
480         }
481
482 do_cleanup:
483         close(sync_fd);
484 }
485
486 TEST_HARNESS_MAIN