~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/uevent/uevent_filtering.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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_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 
 30 ssize_t read_nointr(int fd, void *buf, size_t count)
 31 {
 32         ssize_t ret;
 33 
 34 again:
 35         ret = read(fd, buf, count);
 36         if (ret < 0 && errno == EINTR)
 37                 goto again;
 38 
 39         return ret;
 40 }
 41 
 42 ssize_t write_nointr(int fd, const void *buf, size_t count)
 43 {
 44         ssize_t ret;
 45 
 46 again:
 47         ret = write(fd, buf, count);
 48         if (ret < 0 && errno == EINTR)
 49                 goto again;
 50 
 51         return ret;
 52 }
 53 
 54 int wait_for_pid(pid_t pid)
 55 {
 56         int status, ret;
 57 
 58 again:
 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 
 76 static 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 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                 ret = -1;
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                 ret = -1;
152                 fprintf(stderr, "Failed to synchronize with parent process\n");
153                 goto on_error;
154         }
155 
156         ret = 0;
157         for (;;) {
158                 ssize_t r;
159 
160                 r = recvmsg(sk_fd, &hdr, 0);
161                 if (r <= 0) {
162                         fprintf(stderr, "%s - Failed to receive uevent\n", strerror(errno));
163                         ret = -1;
164                         break;
165                 }
166 
167                 /* ignore libudev messages */
168                 if (memcmp(buf, "libudev", 8) == 0)
169                         continue;
170 
171                 /* ignore uevents we didn't trigger */
172                 if (memcmp(buf, __UEVENT_HEADER, __UEVENT_HEADER_LEN) != 0)
173                         continue;
174 
175                 if (!expect_uevent) {
176                         fprintf(stderr, "Received unexpected uevent:\n");
177                         ret = -1;
178                 }
179 
180                 if (TH_LOG_ENABLED) {
181                         /* If logging is enabled dump the received uevent. */
182                         (void)write_nointr(STDERR_FILENO, buf, r);
183                         (void)write_nointr(STDERR_FILENO, "\n", 1);
184                 }
185 
186                 break;
187         }
188 
189 on_error:
190         close(sk_fd);
191 
192         return ret;
193 }
194 
195 int trigger_uevent(unsigned int times)
196 {
197         int fd, ret;
198         unsigned int i;
199 
200         fd = open(__DEV_FULL, O_RDWR | O_CLOEXEC);
201         if (fd < 0) {
202                 if (errno != ENOENT)
203                         return -EINVAL;
204 
205                 return -1;
206         }
207 
208         for (i = 0; i < times; i++) {
209                 ret = write_nointr(fd, "add\n", sizeof("add\n") - 1);
210                 if (ret < 0) {
211                         fprintf(stderr, "Failed to trigger uevent\n");
212                         break;
213                 }
214         }
215         close(fd);
216 
217         return ret;
218 }
219 
220 int set_death_signal(void)
221 {
222         int ret;
223         pid_t ppid;
224 
225         ret = prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
226 
227         /* Check whether we have been orphaned. */
228         ppid = getppid();
229         if (ppid == 1) {
230                 pid_t self;
231 
232                 self = getpid();
233                 ret = kill(self, SIGKILL);
234         }
235 
236         if (ret < 0)
237                 return -1;
238 
239         return 0;
240 }
241 
242 static int do_test(unsigned long pre_flags, unsigned long post_flags,
243                    bool expect_uevent, int sync_fd)
244 {
245         int ret;
246         uint64_t wait_val;
247         pid_t pid;
248         sigset_t mask;
249         sigset_t orig_mask;
250         struct timespec timeout;
251 
252         sigemptyset(&mask);
253         sigaddset(&mask, SIGCHLD);
254 
255         ret = sigprocmask(SIG_BLOCK, &mask, &orig_mask);
256         if (ret < 0) {
257                 fprintf(stderr, "%s- Failed to block SIGCHLD\n", strerror(errno));
258                 return -1;
259         }
260 
261         pid = fork();
262         if (pid < 0) {
263                 fprintf(stderr, "%s - Failed to fork() new process\n", strerror(errno));
264                 return -1;
265         }
266 
267         if (pid == 0) {
268                 /* Make sure that we go away when our parent dies. */
269                 ret = set_death_signal();
270                 if (ret < 0) {
271                         fprintf(stderr, "Failed to set PR_SET_PDEATHSIG to SIGKILL\n");
272                         _exit(EXIT_FAILURE);
273                 }
274 
275                 if (pre_flags & CLONE_NEWUSER) {
276                         ret = unshare(CLONE_NEWUSER);
277                         if (ret < 0) {
278                                 fprintf(stderr,
279                                         "%s - Failed to unshare user namespace\n",
280                                         strerror(errno));
281                                 _exit(EXIT_FAILURE);
282                         }
283                 }
284 
285                 if (pre_flags & CLONE_NEWNET) {
286                         ret = unshare(CLONE_NEWNET);
287                         if (ret < 0) {
288                                 fprintf(stderr,
289                                         "%s - Failed to unshare network namespace\n",
290                                         strerror(errno));
291                                 _exit(EXIT_FAILURE);
292                         }
293                 }
294 
295                 if (uevent_listener(post_flags, expect_uevent, sync_fd) < 0)
296                         _exit(EXIT_FAILURE);
297 
298                 _exit(EXIT_SUCCESS);
299         }
300 
301         ret = read_nointr(sync_fd, &wait_val, sizeof(wait_val));
302         if (ret != sizeof(wait_val)) {
303                 fprintf(stderr, "Failed to synchronize with child process\n");
304                 _exit(EXIT_FAILURE);
305         }
306 
307         /* Trigger 10 uevents to account for the case where the kernel might
308          * drop some.
309          */
310         ret = trigger_uevent(10);
311         if (ret < 0)
312                 fprintf(stderr, "Failed triggering uevents\n");
313 
314         /* Wait for 2 seconds before considering this failed. This should be
315          * plenty of time for the kernel to deliver the uevent even under heavy
316          * load.
317          */
318         timeout.tv_sec = 2;
319         timeout.tv_nsec = 0;
320 
321 again:
322         ret = sigtimedwait(&mask, NULL, &timeout);
323         if (ret < 0) {
324                 if (errno == EINTR)
325                         goto again;
326 
327                 if (!expect_uevent)
328                         ret = kill(pid, SIGTERM); /* success */
329                 else
330                         ret = kill(pid, SIGUSR1); /* error */
331                 if (ret < 0)
332                         return -1;
333         }
334 
335         ret = wait_for_pid(pid);
336         if (ret < 0)
337                 return -1;
338 
339         return ret;
340 }
341 
342 static void signal_handler(int sig)
343 {
344         if (sig == SIGTERM)
345                 _exit(EXIT_SUCCESS);
346 
347         _exit(EXIT_FAILURE);
348 }
349 
350 TEST(uevent_filtering)
351 {
352         int ret, sync_fd;
353         struct sigaction act;
354 
355         if (geteuid()) {
356                 TH_LOG("Uevent filtering tests require root privileges. Skipping test");
357                 _exit(KSFT_SKIP);
358         }
359 
360         ret = access(__DEV_FULL, F_OK);
361         EXPECT_EQ(0, ret) {
362                 if (errno == ENOENT) {
363                         TH_LOG(__DEV_FULL " does not exist. Skipping test");
364                         _exit(KSFT_SKIP);
365                 }
366 
367                 _exit(KSFT_FAIL);
368         }
369 
370         act.sa_handler = signal_handler;
371         act.sa_flags = 0;
372         sigemptyset(&act.sa_mask);
373 
374         ret = sigaction(SIGTERM, &act, NULL);
375         ASSERT_EQ(0, ret);
376 
377         sync_fd = eventfd(0, EFD_CLOEXEC);
378         ASSERT_GE(sync_fd, 0);
379 
380         /*
381          * Setup:
382          * - Open uevent listening socket in initial network namespace owned by
383          *   initial user namespace.
384          * - Trigger uevent in initial network namespace owned by initial user
385          *   namespace.
386          * Expected Result:
387          * - uevent listening socket receives uevent
388          */
389         ret = do_test(0, 0, true, sync_fd);
390         ASSERT_EQ(0, ret) {
391                 goto do_cleanup;
392         }
393 
394         /*
395          * Setup:
396          * - Open uevent listening socket in non-initial network namespace
397          *   owned by initial user namespace.
398          * - Trigger uevent in initial network namespace owned by initial user
399          *   namespace.
400          * Expected Result:
401          * - uevent listening socket receives uevent
402          */
403         ret = do_test(CLONE_NEWNET, 0, true, sync_fd);
404         ASSERT_EQ(0, ret) {
405                 goto do_cleanup;
406         }
407 
408         /*
409          * Setup:
410          * - unshare user namespace
411          * - Open uevent listening socket in initial network namespace
412          *   owned by initial user namespace.
413          * - Trigger uevent in initial network namespace owned by initial user
414          *   namespace.
415          * Expected Result:
416          * - uevent listening socket receives uevent
417          */
418         ret = do_test(CLONE_NEWUSER, 0, true, sync_fd);
419         ASSERT_EQ(0, ret) {
420                 goto do_cleanup;
421         }
422 
423         /*
424          * Setup:
425          * - Open uevent listening socket in non-initial network namespace
426          *   owned by non-initial user namespace.
427          * - Trigger uevent in initial network namespace owned by initial user
428          *   namespace.
429          * Expected Result:
430          * - uevent listening socket receives no uevent
431          */
432         ret = do_test(CLONE_NEWUSER | CLONE_NEWNET, 0, false, sync_fd);
433         ASSERT_EQ(0, ret) {
434                 goto do_cleanup;
435         }
436 
437         /*
438          * Setup:
439          * - Open uevent listening socket in initial network namespace
440          *   owned by initial user namespace.
441          * - unshare network namespace
442          * - Trigger uevent in initial network namespace owned by initial user
443          *   namespace.
444          * Expected Result:
445          * - uevent listening socket receives uevent
446          */
447         ret = do_test(0, CLONE_NEWNET, true, sync_fd);
448         ASSERT_EQ(0, ret) {
449                 goto do_cleanup;
450         }
451 
452         /*
453          * Setup:
454          * - Open uevent listening socket in initial network namespace
455          *   owned by initial user namespace.
456          * - unshare user namespace
457          * - Trigger uevent in initial network namespace owned by initial user
458          *   namespace.
459          * Expected Result:
460          * - uevent listening socket receives uevent
461          */
462         ret = do_test(0, CLONE_NEWUSER, true, sync_fd);
463         ASSERT_EQ(0, ret) {
464                 goto do_cleanup;
465         }
466 
467         /*
468          * Setup:
469          * - Open uevent listening socket in initial network namespace
470          *   owned by initial user namespace.
471          * - unshare user namespace
472          * - unshare network namespace
473          * - Trigger uevent in initial network namespace owned by initial user
474          *   namespace.
475          * Expected Result:
476          * - uevent listening socket receives uevent
477          */
478         ret = do_test(0, CLONE_NEWUSER | CLONE_NEWNET, true, sync_fd);
479         ASSERT_EQ(0, ret) {
480                 goto do_cleanup;
481         }
482 
483 do_cleanup:
484         close(sync_fd);
485 }
486 
487 TEST_HARNESS_MAIN
488 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php