Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Test for remove_on_exec.
0004  *
0005  * Copyright (C) 2021, Google LLC.
0006  */
0007 
0008 #define _GNU_SOURCE
0009 
0010 /* We need the latest siginfo from the kernel repo. */
0011 #include <sys/types.h>
0012 #include <asm/siginfo.h>
0013 #define __have_siginfo_t 1
0014 #define __have_sigval_t 1
0015 #define __have_sigevent_t 1
0016 #define __siginfo_t_defined
0017 #define __sigval_t_defined
0018 #define __sigevent_t_defined
0019 #define _BITS_SIGINFO_CONSTS_H 1
0020 #define _BITS_SIGEVENT_CONSTS_H 1
0021 
0022 #include <stdbool.h>
0023 #include <stddef.h>
0024 #include <stdint.h>
0025 #include <stdio.h>
0026 #include <linux/perf_event.h>
0027 #include <pthread.h>
0028 #include <signal.h>
0029 #include <sys/ioctl.h>
0030 #include <sys/syscall.h>
0031 #include <unistd.h>
0032 
0033 #include "../kselftest_harness.h"
0034 
0035 static volatile int signal_count;
0036 
0037 static struct perf_event_attr make_event_attr(void)
0038 {
0039     struct perf_event_attr attr = {
0040         .type       = PERF_TYPE_HARDWARE,
0041         .size       = sizeof(attr),
0042         .config     = PERF_COUNT_HW_INSTRUCTIONS,
0043         .sample_period  = 1000,
0044         .exclude_kernel = 1,
0045         .exclude_hv = 1,
0046         .disabled   = 1,
0047         .inherit    = 1,
0048         /*
0049          * Children normally retain their inherited event on exec; with
0050          * remove_on_exec, we'll remove their event, but the parent and
0051          * any other non-exec'd children will keep their events.
0052          */
0053         .remove_on_exec = 1,
0054         .sigtrap    = 1,
0055     };
0056     return attr;
0057 }
0058 
0059 static void sigtrap_handler(int signum, siginfo_t *info, void *ucontext)
0060 {
0061     if (info->si_code != TRAP_PERF) {
0062         fprintf(stderr, "%s: unexpected si_code %d\n", __func__, info->si_code);
0063         return;
0064     }
0065 
0066     signal_count++;
0067 }
0068 
0069 FIXTURE(remove_on_exec)
0070 {
0071     struct sigaction oldact;
0072     int fd;
0073 };
0074 
0075 FIXTURE_SETUP(remove_on_exec)
0076 {
0077     struct perf_event_attr attr = make_event_attr();
0078     struct sigaction action = {};
0079 
0080     signal_count = 0;
0081 
0082     /* Initialize sigtrap handler. */
0083     action.sa_flags = SA_SIGINFO | SA_NODEFER;
0084     action.sa_sigaction = sigtrap_handler;
0085     sigemptyset(&action.sa_mask);
0086     ASSERT_EQ(sigaction(SIGTRAP, &action, &self->oldact), 0);
0087 
0088     /* Initialize perf event. */
0089     self->fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, PERF_FLAG_FD_CLOEXEC);
0090     ASSERT_NE(self->fd, -1);
0091 }
0092 
0093 FIXTURE_TEARDOWN(remove_on_exec)
0094 {
0095     close(self->fd);
0096     sigaction(SIGTRAP, &self->oldact, NULL);
0097 }
0098 
0099 /* Verify event propagates to fork'd child. */
0100 TEST_F(remove_on_exec, fork_only)
0101 {
0102     int status;
0103     pid_t pid = fork();
0104 
0105     if (pid == 0) {
0106         ASSERT_EQ(signal_count, 0);
0107         ASSERT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
0108         while (!signal_count);
0109         _exit(42);
0110     }
0111 
0112     while (!signal_count); /* Child enables event. */
0113     EXPECT_EQ(waitpid(pid, &status, 0), pid);
0114     EXPECT_EQ(WEXITSTATUS(status), 42);
0115 }
0116 
0117 /*
0118  * Verify that event does _not_ propagate to fork+exec'd child; event enabled
0119  * after fork+exec.
0120  */
0121 TEST_F(remove_on_exec, fork_exec_then_enable)
0122 {
0123     pid_t pid_exec, pid_only_fork;
0124     int pipefd[2];
0125     int tmp;
0126 
0127     /*
0128      * Non-exec child, to ensure exec does not affect inherited events of
0129      * other children.
0130      */
0131     pid_only_fork = fork();
0132     if (pid_only_fork == 0) {
0133         /* Block until parent enables event. */
0134         while (!signal_count);
0135         _exit(42);
0136     }
0137 
0138     ASSERT_NE(pipe(pipefd), -1);
0139     pid_exec = fork();
0140     if (pid_exec == 0) {
0141         ASSERT_NE(dup2(pipefd[1], STDOUT_FILENO), -1);
0142         close(pipefd[0]);
0143         execl("/proc/self/exe", "exec_child", NULL);
0144         _exit((perror("exec failed"), 1));
0145     }
0146     close(pipefd[1]);
0147 
0148     ASSERT_EQ(waitpid(pid_exec, &tmp, WNOHANG), 0); /* Child is running. */
0149     /* Wait for exec'd child to start spinning. */
0150     EXPECT_EQ(read(pipefd[0], &tmp, sizeof(int)), sizeof(int));
0151     EXPECT_EQ(tmp, 42);
0152     close(pipefd[0]);
0153     /* Now we can enable the event, knowing the child is doing work. */
0154     EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
0155     /* If the event propagated to the exec'd child, it will exit normally... */
0156     usleep(100000); /* ... give time for event to trigger (in case of bug). */
0157     EXPECT_EQ(waitpid(pid_exec, &tmp, WNOHANG), 0); /* Should still be running. */
0158     EXPECT_EQ(kill(pid_exec, SIGKILL), 0);
0159 
0160     /* Verify removal from child did not affect this task's event. */
0161     tmp = signal_count;
0162     while (signal_count == tmp); /* Should not hang! */
0163     /* Nor should it have affected the first child. */
0164     EXPECT_EQ(waitpid(pid_only_fork, &tmp, 0), pid_only_fork);
0165     EXPECT_EQ(WEXITSTATUS(tmp), 42);
0166 }
0167 
0168 /*
0169  * Verify that event does _not_ propagate to fork+exec'd child; event enabled
0170  * before fork+exec.
0171  */
0172 TEST_F(remove_on_exec, enable_then_fork_exec)
0173 {
0174     pid_t pid_exec;
0175     int tmp;
0176 
0177     EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
0178 
0179     pid_exec = fork();
0180     if (pid_exec == 0) {
0181         execl("/proc/self/exe", "exec_child", NULL);
0182         _exit((perror("exec failed"), 1));
0183     }
0184 
0185     /*
0186      * The child may exit abnormally at any time if the event propagated and
0187      * a SIGTRAP is sent before the handler was set up.
0188      */
0189     usleep(100000); /* ... give time for event to trigger (in case of bug). */
0190     EXPECT_EQ(waitpid(pid_exec, &tmp, WNOHANG), 0); /* Should still be running. */
0191     EXPECT_EQ(kill(pid_exec, SIGKILL), 0);
0192 
0193     /* Verify removal from child did not affect this task's event. */
0194     tmp = signal_count;
0195     while (signal_count == tmp); /* Should not hang! */
0196 }
0197 
0198 TEST_F(remove_on_exec, exec_stress)
0199 {
0200     pid_t pids[30];
0201     int i, tmp;
0202 
0203     for (i = 0; i < sizeof(pids) / sizeof(pids[0]); i++) {
0204         pids[i] = fork();
0205         if (pids[i] == 0) {
0206             execl("/proc/self/exe", "exec_child", NULL);
0207             _exit((perror("exec failed"), 1));
0208         }
0209 
0210         /* Some forked with event disabled, rest with enabled. */
0211         if (i > 10)
0212             EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_ENABLE, 0), 0);
0213     }
0214 
0215     usleep(100000); /* ... give time for event to trigger (in case of bug). */
0216 
0217     for (i = 0; i < sizeof(pids) / sizeof(pids[0]); i++) {
0218         /* All children should still be running. */
0219         EXPECT_EQ(waitpid(pids[i], &tmp, WNOHANG), 0);
0220         EXPECT_EQ(kill(pids[i], SIGKILL), 0);
0221     }
0222 
0223     /* Verify event is still alive. */
0224     tmp = signal_count;
0225     while (signal_count == tmp);
0226 }
0227 
0228 /* For exec'd child. */
0229 static void exec_child(void)
0230 {
0231     struct sigaction action = {};
0232     const int val = 42;
0233 
0234     /* Set up sigtrap handler in case we erroneously receive a trap. */
0235     action.sa_flags = SA_SIGINFO | SA_NODEFER;
0236     action.sa_sigaction = sigtrap_handler;
0237     sigemptyset(&action.sa_mask);
0238     if (sigaction(SIGTRAP, &action, NULL))
0239         _exit((perror("sigaction failed"), 1));
0240 
0241     /* Signal parent that we're starting to spin. */
0242     if (write(STDOUT_FILENO, &val, sizeof(int)) == -1)
0243         _exit((perror("write failed"), 1));
0244 
0245     /* Should hang here until killed. */
0246     while (!signal_count);
0247 }
0248 
0249 #define main test_main
0250 TEST_HARNESS_MAIN
0251 #undef main
0252 int main(int argc, char *argv[])
0253 {
0254     if (!strcmp(argv[0], "exec_child")) {
0255         exec_child();
0256         return 1;
0257     }
0258 
0259     return test_main(argc, argv);
0260 }