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.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
  31ssize_t read_nointr(int fd, void *buf, size_t count)
  32{
  33        ssize_t ret;
  34
  35again:
  36        ret = read(fd, buf, count);
  37        if (ret < 0 && errno == EINTR)
  38                goto again;
  39
  40        return ret;
  41}
  42
  43ssize_t write_nointr(int fd, const void *buf, size_t count)
  44{
  45        ssize_t ret;
  46
  47again:
  48        ret = write(fd, buf, count);
  49        if (ret < 0 && errno == EINTR)
  50                goto again;
  51
  52        return ret;
  53}
  54
  55int wait_for_pid(pid_t pid)
  56{
  57        int status, ret;
  58
  59again:
  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
  77static 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
 188on_error:
 189        close(sk_fd);
 190
 191        return fret;
 192}
 193
 194int 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
 219int 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
 241static 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
 320again:
 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
 341static void signal_handler(int sig)
 342{
 343        if (sig == SIGTERM)
 344                _exit(EXIT_SUCCESS);
 345
 346        _exit(EXIT_FAILURE);
 347}
 348
 349TEST(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
 482do_cleanup:
 483        close(sync_fd);
 484}
 485
 486TEST_HARNESS_MAIN
 487