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