linux/tools/testing/selftests/perf_events/remove_on_exec.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Test for remove_on_exec.
   4 *
   5 * Copyright (C) 2021, Google LLC.
   6 */
   7
   8#define _GNU_SOURCE
   9
  10/* We need the latest siginfo from the kernel repo. */
  11#include <sys/types.h>
  12#include <asm/siginfo.h>
  13#define __have_siginfo_t 1
  14#define __have_sigval_t 1
  15#define __have_sigevent_t 1
  16#define __siginfo_t_defined
  17#define __sigval_t_defined
  18#define __sigevent_t_defined
  19#define _BITS_SIGINFO_CONSTS_H 1
  20#define _BITS_SIGEVENT_CONSTS_H 1
  21
  22#include <stdbool.h>
  23#include <stddef.h>
  24#include <stdint.h>
  25#include <stdio.h>
  26#include <linux/perf_event.h>
  27#include <pthread.h>
  28#include <signal.h>
  29#include <sys/ioctl.h>
  30#include <sys/syscall.h>
  31#include <unistd.h>
  32
  33#include "../kselftest_harness.h"
  34
  35static volatile int signal_count;
  36
  37static struct perf_event_attr make_event_attr(void)
  38{
  39        struct perf_event_attr attr = {
  40                .type           = PERF_TYPE_HARDWARE,
  41                .size           = sizeof(attr),
  42                .config         = PERF_COUNT_HW_INSTRUCTIONS,
  43                .sample_period  = 1000,
  44                .exclude_kernel = 1,
  45                .exclude_hv     = 1,
  46                .disabled       = 1,
  47                .inherit        = 1,
  48                /*
  49                 * Children normally retain their inherited event on exec; with
  50                 * remove_on_exec, we'll remove their event, but the parent and
  51                 * any other non-exec'd children will keep their events.
  52                 */
  53                .remove_on_exec = 1,
  54                .sigtrap        = 1,
  55        };
  56        return attr;
  57}
  58
  59static void sigtrap_handler(int signum, siginfo_t *info, void *ucontext)
  60{
  61        if (info->si_code != TRAP_PERF) {
  62                fprintf(stderr, "%s: unexpected si_code %d\n", __func__, info->si_code);
  63                return;
  64        }
  65
  66        signal_count++;
  67}
  68
  69FIXTURE(remove_on_exec)
  70{
  71        struct sigaction oldact;
  72        int fd;
  73};
  74
  75FIXTURE_SETUP(remove_on_exec)
  76{
  77        struct perf_event_attr attr = make_event_attr();
  78        struct sigaction action = {};
  79
  80        signal_count = 0;
  81
  82        /* Initialize sigtrap handler. */
  83        action.sa_flags = SA_SIGINFO | SA_NODEFER;
  84        action.sa_sigaction = sigtrap_handler;
  85        sigemptyset(&action.sa_mask);
  86        ASSERT_EQ(sigaction(SIGTRAP, &action, &self->oldact), 0);
  87
  88        /* Initialize perf event. */
  89        self->fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, PERF_FLAG_FD_CLOEXEC);
  90        ASSERT_NE(self->fd, -1);
  91}
  92
  93FIXTURE_TEARDOWN(remove_on_exec)
  94{
  95        close(self->fd);
  96        sigaction(SIGTRAP, &self->oldact, NULL);
  97}
  98
  99/* Verify event propagates to fork'd child. */
 100TEST_F(remove_on_exec, fork_only)
 101{
 102        int status;
 103        pid_t pid = fork();
 104
 105        if (pid == 0) {
 106                ASSERT_EQ(signal_count, 0);
 107                ASSERT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
 108                while (!signal_count);
 109                _exit(42);
 110        }
 111
 112        while (!signal_count); /* Child enables event. */
 113        EXPECT_EQ(waitpid(pid, &status, 0), pid);
 114        EXPECT_EQ(WEXITSTATUS(status), 42);
 115}
 116
 117/*
 118 * Verify that event does _not_ propagate to fork+exec'd child; event enabled
 119 * after fork+exec.
 120 */
 121TEST_F(remove_on_exec, fork_exec_then_enable)
 122{
 123        pid_t pid_exec, pid_only_fork;
 124        int pipefd[2];
 125        int tmp;
 126
 127        /*
 128         * Non-exec child, to ensure exec does not affect inherited events of
 129         * other children.
 130         */
 131        pid_only_fork = fork();
 132        if (pid_only_fork == 0) {
 133                /* Block until parent enables event. */
 134                while (!signal_count);
 135                _exit(42);
 136        }
 137
 138        ASSERT_NE(pipe(pipefd), -1);
 139        pid_exec = fork();
 140        if (pid_exec == 0) {
 141                ASSERT_NE(dup2(pipefd[1], STDOUT_FILENO), -1);
 142                close(pipefd[0]);
 143                execl("/proc/self/exe", "exec_child", NULL);
 144                _exit((perror("exec failed"), 1));
 145        }
 146        close(pipefd[1]);
 147
 148        ASSERT_EQ(waitpid(pid_exec, &tmp, WNOHANG), 0); /* Child is running. */
 149        /* Wait for exec'd child to start spinning. */
 150        EXPECT_EQ(read(pipefd[0], &tmp, sizeof(int)), sizeof(int));
 151        EXPECT_EQ(tmp, 42);
 152        close(pipefd[0]);
 153        /* Now we can enable the event, knowing the child is doing work. */
 154        EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
 155        /* If the event propagated to the exec'd child, it will exit normally... */
 156        usleep(100000); /* ... give time for event to trigger (in case of bug). */
 157        EXPECT_EQ(waitpid(pid_exec, &tmp, WNOHANG), 0); /* Should still be running. */
 158        EXPECT_EQ(kill(pid_exec, SIGKILL), 0);
 159
 160        /* Verify removal from child did not affect this task's event. */
 161        tmp = signal_count;
 162        while (signal_count == tmp); /* Should not hang! */
 163        /* Nor should it have affected the first child. */
 164        EXPECT_EQ(waitpid(pid_only_fork, &tmp, 0), pid_only_fork);
 165        EXPECT_EQ(WEXITSTATUS(tmp), 42);
 166}
 167
 168/*
 169 * Verify that event does _not_ propagate to fork+exec'd child; event enabled
 170 * before fork+exec.
 171 */
 172TEST_F(remove_on_exec, enable_then_fork_exec)
 173{
 174        pid_t pid_exec;
 175        int tmp;
 176
 177        EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
 178
 179        pid_exec = fork();
 180        if (pid_exec == 0) {
 181                execl("/proc/self/exe", "exec_child", NULL);
 182                _exit((perror("exec failed"), 1));
 183        }
 184
 185        /*
 186         * The child may exit abnormally at any time if the event propagated and
 187         * a SIGTRAP is sent before the handler was set up.
 188         */
 189        usleep(100000); /* ... give time for event to trigger (in case of bug). */
 190        EXPECT_EQ(waitpid(pid_exec, &tmp, WNOHANG), 0); /* Should still be running. */
 191        EXPECT_EQ(kill(pid_exec, SIGKILL), 0);
 192
 193        /* Verify removal from child did not affect this task's event. */
 194        tmp = signal_count;
 195        while (signal_count == tmp); /* Should not hang! */
 196}
 197
 198TEST_F(remove_on_exec, exec_stress)
 199{
 200        pid_t pids[30];
 201        int i, tmp;
 202
 203        for (i = 0; i < sizeof(pids) / sizeof(pids[0]); i++) {
 204                pids[i] = fork();
 205                if (pids[i] == 0) {
 206                        execl("/proc/self/exe", "exec_child", NULL);
 207                        _exit((perror("exec failed"), 1));
 208                }
 209
 210                /* Some forked with event disabled, rest with enabled. */
 211                if (i > 10)
 212                        EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
 213        }
 214
 215        usleep(100000); /* ... give time for event to trigger (in case of bug). */
 216
 217        for (i = 0; i < sizeof(pids) / sizeof(pids[0]); i++) {
 218                /* All children should still be running. */
 219                EXPECT_EQ(waitpid(pids[i], &tmp, WNOHANG), 0);
 220                EXPECT_EQ(kill(pids[i], SIGKILL), 0);
 221        }
 222
 223        /* Verify event is still alive. */
 224        tmp = signal_count;
 225        while (signal_count == tmp);
 226}
 227
 228/* For exec'd child. */
 229static void exec_child(void)
 230{
 231        struct sigaction action = {};
 232        const int val = 42;
 233
 234        /* Set up sigtrap handler in case we erroneously receive a trap. */
 235        action.sa_flags = SA_SIGINFO | SA_NODEFER;
 236        action.sa_sigaction = sigtrap_handler;
 237        sigemptyset(&action.sa_mask);
 238        if (sigaction(SIGTRAP, &action, NULL))
 239                _exit((perror("sigaction failed"), 1));
 240
 241        /* Signal parent that we're starting to spin. */
 242        if (write(STDOUT_FILENO, &val, sizeof(int)) == -1)
 243                _exit((perror("write failed"), 1));
 244
 245        /* Should hang here until killed. */
 246        while (!signal_count);
 247}
 248
 249#define main test_main
 250TEST_HARNESS_MAIN
 251#undef main
 252int main(int argc, char *argv[])
 253{
 254        if (!strcmp(argv[0], "exec_child")) {
 255                exec_child();
 256                return 1;
 257        }
 258
 259        return test_main(argc, argv);
 260}
 261