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

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

Version: ~ [ linux-5.1-rc1 ] ~ [ linux-5.0.3 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.30 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.107 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.164 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.176 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.136 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.63 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ 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.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
487 

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | 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.

osdn.jp