root/tools/testing/selftests/uevent/uevent_filtering.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. read_nointr
  2. write_nointr
  3. wait_for_pid
  4. uevent_listener
  5. trigger_uevent
  6. set_death_signal
  7. do_test
  8. signal_handler
  9. TEST

   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

/* [<][>][^][v][top][bottom][index][help] */