1575a0ae9SChristian Brauner /* SPDX-License-Identifier: GPL-2.0 */ 2575a0ae9SChristian Brauner 3575a0ae9SChristian Brauner #define _GNU_SOURCE 4575a0ae9SChristian Brauner #include <errno.h> 5575a0ae9SChristian Brauner #include <fcntl.h> 6575a0ae9SChristian Brauner #include <linux/types.h> 7*740378dcSJoel Fernandes (Google) #include <pthread.h> 8575a0ae9SChristian Brauner #include <sched.h> 9575a0ae9SChristian Brauner #include <signal.h> 10575a0ae9SChristian Brauner #include <stdio.h> 11575a0ae9SChristian Brauner #include <stdlib.h> 12575a0ae9SChristian Brauner #include <string.h> 13575a0ae9SChristian Brauner #include <syscall.h> 14*740378dcSJoel Fernandes (Google) #include <sys/epoll.h> 15*740378dcSJoel Fernandes (Google) #include <sys/mman.h> 16575a0ae9SChristian Brauner #include <sys/mount.h> 17575a0ae9SChristian Brauner #include <sys/wait.h> 18*740378dcSJoel Fernandes (Google) #include <time.h> 19575a0ae9SChristian Brauner #include <unistd.h> 20575a0ae9SChristian Brauner 21575a0ae9SChristian Brauner #include "../kselftest.h" 22575a0ae9SChristian Brauner 23*740378dcSJoel Fernandes (Google) #define str(s) _str(s) 24*740378dcSJoel Fernandes (Google) #define _str(s) #s 25*740378dcSJoel Fernandes (Google) #define CHILD_THREAD_MIN_WAIT 3 /* seconds */ 26*740378dcSJoel Fernandes (Google) 27*740378dcSJoel Fernandes (Google) #define MAX_EVENTS 5 28*740378dcSJoel Fernandes (Google) #ifndef __NR_pidfd_send_signal 29*740378dcSJoel Fernandes (Google) #define __NR_pidfd_send_signal 424 30*740378dcSJoel Fernandes (Google) #endif 31*740378dcSJoel Fernandes (Google) 32*740378dcSJoel Fernandes (Google) #ifndef CLONE_PIDFD 33*740378dcSJoel Fernandes (Google) #define CLONE_PIDFD 0x00001000 34*740378dcSJoel Fernandes (Google) #endif 35*740378dcSJoel Fernandes (Google) 36*740378dcSJoel Fernandes (Google) static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *)) 37*740378dcSJoel Fernandes (Google) { 38*740378dcSJoel Fernandes (Google) size_t stack_size = 1024; 39*740378dcSJoel Fernandes (Google) char *stack[1024] = { 0 }; 40*740378dcSJoel Fernandes (Google) 41*740378dcSJoel Fernandes (Google) #ifdef __ia64__ 42*740378dcSJoel Fernandes (Google) return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd); 43*740378dcSJoel Fernandes (Google) #else 44*740378dcSJoel Fernandes (Google) return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd); 45*740378dcSJoel Fernandes (Google) #endif 46*740378dcSJoel Fernandes (Google) } 47*740378dcSJoel Fernandes (Google) 48575a0ae9SChristian Brauner static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, 49575a0ae9SChristian Brauner unsigned int flags) 50575a0ae9SChristian Brauner { 51575a0ae9SChristian Brauner return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); 52575a0ae9SChristian Brauner } 53575a0ae9SChristian Brauner 54575a0ae9SChristian Brauner static int signal_received; 55575a0ae9SChristian Brauner 56575a0ae9SChristian Brauner static void set_signal_received_on_sigusr1(int sig) 57575a0ae9SChristian Brauner { 58575a0ae9SChristian Brauner if (sig == SIGUSR1) 59575a0ae9SChristian Brauner signal_received = 1; 60575a0ae9SChristian Brauner } 61575a0ae9SChristian Brauner 62575a0ae9SChristian Brauner /* 63575a0ae9SChristian Brauner * Straightforward test to see whether pidfd_send_signal() works is to send 64575a0ae9SChristian Brauner * a signal to ourself. 65575a0ae9SChristian Brauner */ 66575a0ae9SChristian Brauner static int test_pidfd_send_signal_simple_success(void) 67575a0ae9SChristian Brauner { 68575a0ae9SChristian Brauner int pidfd, ret; 69575a0ae9SChristian Brauner const char *test_name = "pidfd_send_signal send SIGUSR1"; 70575a0ae9SChristian Brauner 71575a0ae9SChristian Brauner pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC); 72575a0ae9SChristian Brauner if (pidfd < 0) 73575a0ae9SChristian Brauner ksft_exit_fail_msg( 74575a0ae9SChristian Brauner "%s test: Failed to open process file descriptor\n", 75575a0ae9SChristian Brauner test_name); 76575a0ae9SChristian Brauner 77575a0ae9SChristian Brauner signal(SIGUSR1, set_signal_received_on_sigusr1); 78575a0ae9SChristian Brauner 79575a0ae9SChristian Brauner ret = sys_pidfd_send_signal(pidfd, SIGUSR1, NULL, 0); 80575a0ae9SChristian Brauner close(pidfd); 81575a0ae9SChristian Brauner if (ret < 0) 82575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to send signal\n", 83575a0ae9SChristian Brauner test_name); 84575a0ae9SChristian Brauner 85575a0ae9SChristian Brauner if (signal_received != 1) 86575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to receive signal\n", 87575a0ae9SChristian Brauner test_name); 88575a0ae9SChristian Brauner 89575a0ae9SChristian Brauner signal_received = 0; 90575a0ae9SChristian Brauner ksft_test_result_pass("%s test: Sent signal\n", test_name); 91575a0ae9SChristian Brauner return 0; 92575a0ae9SChristian Brauner } 93575a0ae9SChristian Brauner 94575a0ae9SChristian Brauner static int wait_for_pid(pid_t pid) 95575a0ae9SChristian Brauner { 96575a0ae9SChristian Brauner int status, ret; 97575a0ae9SChristian Brauner 98575a0ae9SChristian Brauner again: 99575a0ae9SChristian Brauner ret = waitpid(pid, &status, 0); 100575a0ae9SChristian Brauner if (ret == -1) { 101575a0ae9SChristian Brauner if (errno == EINTR) 102575a0ae9SChristian Brauner goto again; 103575a0ae9SChristian Brauner 104575a0ae9SChristian Brauner return -1; 105575a0ae9SChristian Brauner } 106575a0ae9SChristian Brauner 107575a0ae9SChristian Brauner if (ret != pid) 108575a0ae9SChristian Brauner goto again; 109575a0ae9SChristian Brauner 110575a0ae9SChristian Brauner if (!WIFEXITED(status)) 111575a0ae9SChristian Brauner return -1; 112575a0ae9SChristian Brauner 113575a0ae9SChristian Brauner return WEXITSTATUS(status); 114575a0ae9SChristian Brauner } 115575a0ae9SChristian Brauner 116575a0ae9SChristian Brauner static int test_pidfd_send_signal_exited_fail(void) 117575a0ae9SChristian Brauner { 118575a0ae9SChristian Brauner int pidfd, ret, saved_errno; 119575a0ae9SChristian Brauner char buf[256]; 120575a0ae9SChristian Brauner pid_t pid; 121575a0ae9SChristian Brauner const char *test_name = "pidfd_send_signal signal exited process"; 122575a0ae9SChristian Brauner 123575a0ae9SChristian Brauner pid = fork(); 124575a0ae9SChristian Brauner if (pid < 0) 125575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to create new process\n", 126575a0ae9SChristian Brauner test_name); 127575a0ae9SChristian Brauner 128575a0ae9SChristian Brauner if (pid == 0) 129575a0ae9SChristian Brauner _exit(EXIT_SUCCESS); 130575a0ae9SChristian Brauner 131575a0ae9SChristian Brauner snprintf(buf, sizeof(buf), "/proc/%d", pid); 132575a0ae9SChristian Brauner 133575a0ae9SChristian Brauner pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); 134575a0ae9SChristian Brauner 135575a0ae9SChristian Brauner (void)wait_for_pid(pid); 136575a0ae9SChristian Brauner 137575a0ae9SChristian Brauner if (pidfd < 0) 138575a0ae9SChristian Brauner ksft_exit_fail_msg( 139575a0ae9SChristian Brauner "%s test: Failed to open process file descriptor\n", 140575a0ae9SChristian Brauner test_name); 141575a0ae9SChristian Brauner 142575a0ae9SChristian Brauner ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); 143575a0ae9SChristian Brauner saved_errno = errno; 144575a0ae9SChristian Brauner close(pidfd); 145575a0ae9SChristian Brauner if (ret == 0) 146575a0ae9SChristian Brauner ksft_exit_fail_msg( 147575a0ae9SChristian Brauner "%s test: Managed to send signal to process even though it should have failed\n", 148575a0ae9SChristian Brauner test_name); 149575a0ae9SChristian Brauner 150575a0ae9SChristian Brauner if (saved_errno != ESRCH) 151575a0ae9SChristian Brauner ksft_exit_fail_msg( 152575a0ae9SChristian Brauner "%s test: Expected to receive ESRCH as errno value but received %d instead\n", 153575a0ae9SChristian Brauner test_name, saved_errno); 154575a0ae9SChristian Brauner 155575a0ae9SChristian Brauner ksft_test_result_pass("%s test: Failed to send signal as expected\n", 156575a0ae9SChristian Brauner test_name); 157575a0ae9SChristian Brauner return 0; 158575a0ae9SChristian Brauner } 159575a0ae9SChristian Brauner 160575a0ae9SChristian Brauner /* 161575a0ae9SChristian Brauner * The kernel reserves 300 pids via RESERVED_PIDS in kernel/pid.c 162575a0ae9SChristian Brauner * That means, when it wraps around any pid < 300 will be skipped. 163575a0ae9SChristian Brauner * So we need to use a pid > 300 in order to test recycling. 164575a0ae9SChristian Brauner */ 165575a0ae9SChristian Brauner #define PID_RECYCLE 1000 166575a0ae9SChristian Brauner 167575a0ae9SChristian Brauner /* 168575a0ae9SChristian Brauner * Maximum number of cycles we allow. This is equivalent to PID_MAX_DEFAULT. 169575a0ae9SChristian Brauner * If users set a higher limit or we have cycled PIDFD_MAX_DEFAULT number of 170575a0ae9SChristian Brauner * times then we skip the test to not go into an infinite loop or block for a 171575a0ae9SChristian Brauner * long time. 172575a0ae9SChristian Brauner */ 173575a0ae9SChristian Brauner #define PIDFD_MAX_DEFAULT 0x8000 174575a0ae9SChristian Brauner 175575a0ae9SChristian Brauner /* 176575a0ae9SChristian Brauner * Define a few custom error codes for the child process to clearly indicate 177575a0ae9SChristian Brauner * what is happening. This way we can tell the difference between a system 178575a0ae9SChristian Brauner * error, a test error, etc. 179575a0ae9SChristian Brauner */ 180575a0ae9SChristian Brauner #define PIDFD_PASS 0 181575a0ae9SChristian Brauner #define PIDFD_FAIL 1 182575a0ae9SChristian Brauner #define PIDFD_ERROR 2 183575a0ae9SChristian Brauner #define PIDFD_SKIP 3 184575a0ae9SChristian Brauner #define PIDFD_XFAIL 4 185575a0ae9SChristian Brauner 186575a0ae9SChristian Brauner static int test_pidfd_send_signal_recycled_pid_fail(void) 187575a0ae9SChristian Brauner { 188575a0ae9SChristian Brauner int i, ret; 189575a0ae9SChristian Brauner pid_t pid1; 190575a0ae9SChristian Brauner const char *test_name = "pidfd_send_signal signal recycled pid"; 191575a0ae9SChristian Brauner 192575a0ae9SChristian Brauner ret = unshare(CLONE_NEWPID); 193575a0ae9SChristian Brauner if (ret < 0) 194575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to unshare pid namespace\n", 195575a0ae9SChristian Brauner test_name); 196575a0ae9SChristian Brauner 197575a0ae9SChristian Brauner ret = unshare(CLONE_NEWNS); 198575a0ae9SChristian Brauner if (ret < 0) 199575a0ae9SChristian Brauner ksft_exit_fail_msg( 200575a0ae9SChristian Brauner "%s test: Failed to unshare mount namespace\n", 201575a0ae9SChristian Brauner test_name); 202575a0ae9SChristian Brauner 203575a0ae9SChristian Brauner ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0); 204575a0ae9SChristian Brauner if (ret < 0) 205575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to remount / private\n", 206575a0ae9SChristian Brauner test_name); 207575a0ae9SChristian Brauner 208575a0ae9SChristian Brauner /* pid 1 in new pid namespace */ 209575a0ae9SChristian Brauner pid1 = fork(); 210575a0ae9SChristian Brauner if (pid1 < 0) 211575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to create new process\n", 212575a0ae9SChristian Brauner test_name); 213575a0ae9SChristian Brauner 214575a0ae9SChristian Brauner if (pid1 == 0) { 215575a0ae9SChristian Brauner char buf[256]; 216575a0ae9SChristian Brauner pid_t pid2; 217575a0ae9SChristian Brauner int pidfd = -1; 218575a0ae9SChristian Brauner 219575a0ae9SChristian Brauner (void)umount2("/proc", MNT_DETACH); 220575a0ae9SChristian Brauner ret = mount("proc", "/proc", "proc", 0, NULL); 221575a0ae9SChristian Brauner if (ret < 0) 222575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 223575a0ae9SChristian Brauner 224575a0ae9SChristian Brauner /* grab pid PID_RECYCLE */ 225575a0ae9SChristian Brauner for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) { 226575a0ae9SChristian Brauner pid2 = fork(); 227575a0ae9SChristian Brauner if (pid2 < 0) 228575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 229575a0ae9SChristian Brauner 230575a0ae9SChristian Brauner if (pid2 == 0) 231575a0ae9SChristian Brauner _exit(PIDFD_PASS); 232575a0ae9SChristian Brauner 233575a0ae9SChristian Brauner if (pid2 == PID_RECYCLE) { 234575a0ae9SChristian Brauner snprintf(buf, sizeof(buf), "/proc/%d", pid2); 235575a0ae9SChristian Brauner ksft_print_msg("pid to recycle is %d\n", pid2); 236575a0ae9SChristian Brauner pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); 237575a0ae9SChristian Brauner } 238575a0ae9SChristian Brauner 239575a0ae9SChristian Brauner if (wait_for_pid(pid2)) 240575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 241575a0ae9SChristian Brauner 242575a0ae9SChristian Brauner if (pid2 >= PID_RECYCLE) 243575a0ae9SChristian Brauner break; 244575a0ae9SChristian Brauner } 245575a0ae9SChristian Brauner 246575a0ae9SChristian Brauner /* 247575a0ae9SChristian Brauner * We want to be as predictable as we can so if we haven't been 248575a0ae9SChristian Brauner * able to grab pid PID_RECYCLE skip the test. 249575a0ae9SChristian Brauner */ 250575a0ae9SChristian Brauner if (pid2 != PID_RECYCLE) { 251575a0ae9SChristian Brauner /* skip test */ 252575a0ae9SChristian Brauner close(pidfd); 253575a0ae9SChristian Brauner _exit(PIDFD_SKIP); 254575a0ae9SChristian Brauner } 255575a0ae9SChristian Brauner 256575a0ae9SChristian Brauner if (pidfd < 0) 257575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 258575a0ae9SChristian Brauner 259575a0ae9SChristian Brauner for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) { 260575a0ae9SChristian Brauner char c; 261575a0ae9SChristian Brauner int pipe_fds[2]; 262575a0ae9SChristian Brauner pid_t recycled_pid; 263575a0ae9SChristian Brauner int child_ret = PIDFD_PASS; 264575a0ae9SChristian Brauner 265575a0ae9SChristian Brauner ret = pipe2(pipe_fds, O_CLOEXEC); 266575a0ae9SChristian Brauner if (ret < 0) 267575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 268575a0ae9SChristian Brauner 269575a0ae9SChristian Brauner recycled_pid = fork(); 270575a0ae9SChristian Brauner if (recycled_pid < 0) 271575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 272575a0ae9SChristian Brauner 273575a0ae9SChristian Brauner if (recycled_pid == 0) { 274575a0ae9SChristian Brauner close(pipe_fds[1]); 275575a0ae9SChristian Brauner (void)read(pipe_fds[0], &c, 1); 276575a0ae9SChristian Brauner close(pipe_fds[0]); 277575a0ae9SChristian Brauner 278575a0ae9SChristian Brauner _exit(PIDFD_PASS); 279575a0ae9SChristian Brauner } 280575a0ae9SChristian Brauner 281575a0ae9SChristian Brauner /* 282575a0ae9SChristian Brauner * Stop the child so we can inspect whether we have 283575a0ae9SChristian Brauner * recycled pid PID_RECYCLE. 284575a0ae9SChristian Brauner */ 285575a0ae9SChristian Brauner close(pipe_fds[0]); 286575a0ae9SChristian Brauner ret = kill(recycled_pid, SIGSTOP); 287575a0ae9SChristian Brauner close(pipe_fds[1]); 288575a0ae9SChristian Brauner if (ret) { 289575a0ae9SChristian Brauner (void)wait_for_pid(recycled_pid); 290575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 291575a0ae9SChristian Brauner } 292575a0ae9SChristian Brauner 293575a0ae9SChristian Brauner /* 294575a0ae9SChristian Brauner * We have recycled the pid. Try to signal it. This 295575a0ae9SChristian Brauner * needs to fail since this is a different process than 296575a0ae9SChristian Brauner * the one the pidfd refers to. 297575a0ae9SChristian Brauner */ 298575a0ae9SChristian Brauner if (recycled_pid == PID_RECYCLE) { 299575a0ae9SChristian Brauner ret = sys_pidfd_send_signal(pidfd, SIGCONT, 300575a0ae9SChristian Brauner NULL, 0); 301575a0ae9SChristian Brauner if (ret && errno == ESRCH) 302575a0ae9SChristian Brauner child_ret = PIDFD_XFAIL; 303575a0ae9SChristian Brauner else 304575a0ae9SChristian Brauner child_ret = PIDFD_FAIL; 305575a0ae9SChristian Brauner } 306575a0ae9SChristian Brauner 307575a0ae9SChristian Brauner /* let the process move on */ 308575a0ae9SChristian Brauner ret = kill(recycled_pid, SIGCONT); 309575a0ae9SChristian Brauner if (ret) 310575a0ae9SChristian Brauner (void)kill(recycled_pid, SIGKILL); 311575a0ae9SChristian Brauner 312575a0ae9SChristian Brauner if (wait_for_pid(recycled_pid)) 313575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 314575a0ae9SChristian Brauner 315575a0ae9SChristian Brauner switch (child_ret) { 316575a0ae9SChristian Brauner case PIDFD_FAIL: 317575a0ae9SChristian Brauner /* fallthrough */ 318575a0ae9SChristian Brauner case PIDFD_XFAIL: 319575a0ae9SChristian Brauner _exit(child_ret); 320575a0ae9SChristian Brauner case PIDFD_PASS: 321575a0ae9SChristian Brauner break; 322575a0ae9SChristian Brauner default: 323575a0ae9SChristian Brauner /* not reached */ 324575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 325575a0ae9SChristian Brauner } 326575a0ae9SChristian Brauner 327575a0ae9SChristian Brauner /* 328575a0ae9SChristian Brauner * If the user set a custom pid_max limit we could be 329575a0ae9SChristian Brauner * in the millions. 330575a0ae9SChristian Brauner * Skip the test in this case. 331575a0ae9SChristian Brauner */ 332575a0ae9SChristian Brauner if (recycled_pid > PIDFD_MAX_DEFAULT) 333575a0ae9SChristian Brauner _exit(PIDFD_SKIP); 334575a0ae9SChristian Brauner } 335575a0ae9SChristian Brauner 336575a0ae9SChristian Brauner /* failed to recycle pid */ 337575a0ae9SChristian Brauner _exit(PIDFD_SKIP); 338575a0ae9SChristian Brauner } 339575a0ae9SChristian Brauner 340575a0ae9SChristian Brauner ret = wait_for_pid(pid1); 341575a0ae9SChristian Brauner switch (ret) { 342575a0ae9SChristian Brauner case PIDFD_FAIL: 343575a0ae9SChristian Brauner ksft_exit_fail_msg( 344575a0ae9SChristian Brauner "%s test: Managed to signal recycled pid %d\n", 345575a0ae9SChristian Brauner test_name, PID_RECYCLE); 346575a0ae9SChristian Brauner case PIDFD_PASS: 347575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to recycle pid %d\n", 348575a0ae9SChristian Brauner test_name, PID_RECYCLE); 349575a0ae9SChristian Brauner case PIDFD_SKIP: 350575a0ae9SChristian Brauner ksft_print_msg("%s test: Skipping test\n", test_name); 351575a0ae9SChristian Brauner ret = 0; 352575a0ae9SChristian Brauner break; 353575a0ae9SChristian Brauner case PIDFD_XFAIL: 354575a0ae9SChristian Brauner ksft_test_result_pass( 355575a0ae9SChristian Brauner "%s test: Failed to signal recycled pid as expected\n", 356575a0ae9SChristian Brauner test_name); 357575a0ae9SChristian Brauner ret = 0; 358575a0ae9SChristian Brauner break; 359575a0ae9SChristian Brauner default /* PIDFD_ERROR */: 360575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Error while running tests\n", 361575a0ae9SChristian Brauner test_name); 362575a0ae9SChristian Brauner } 363575a0ae9SChristian Brauner 364575a0ae9SChristian Brauner return ret; 365575a0ae9SChristian Brauner } 366575a0ae9SChristian Brauner 367575a0ae9SChristian Brauner static int test_pidfd_send_signal_syscall_support(void) 368575a0ae9SChristian Brauner { 369575a0ae9SChristian Brauner int pidfd, ret; 370575a0ae9SChristian Brauner const char *test_name = "pidfd_send_signal check for support"; 371575a0ae9SChristian Brauner 372575a0ae9SChristian Brauner pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC); 373575a0ae9SChristian Brauner if (pidfd < 0) 374575a0ae9SChristian Brauner ksft_exit_fail_msg( 375575a0ae9SChristian Brauner "%s test: Failed to open process file descriptor\n", 376575a0ae9SChristian Brauner test_name); 377575a0ae9SChristian Brauner 378575a0ae9SChristian Brauner ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); 379575a0ae9SChristian Brauner if (ret < 0) { 380575a0ae9SChristian Brauner /* 381575a0ae9SChristian Brauner * pidfd_send_signal() will currently return ENOSYS when 382575a0ae9SChristian Brauner * CONFIG_PROC_FS is not set. 383575a0ae9SChristian Brauner */ 384575a0ae9SChristian Brauner if (errno == ENOSYS) 385575a0ae9SChristian Brauner ksft_exit_skip( 386575a0ae9SChristian Brauner "%s test: pidfd_send_signal() syscall not supported (Ensure that CONFIG_PROC_FS=y is set)\n", 387575a0ae9SChristian Brauner test_name); 388575a0ae9SChristian Brauner 389575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to send signal\n", 390575a0ae9SChristian Brauner test_name); 391575a0ae9SChristian Brauner } 392575a0ae9SChristian Brauner 393575a0ae9SChristian Brauner close(pidfd); 394575a0ae9SChristian Brauner ksft_test_result_pass( 395575a0ae9SChristian Brauner "%s test: pidfd_send_signal() syscall is supported. Tests can be executed\n", 396575a0ae9SChristian Brauner test_name); 397575a0ae9SChristian Brauner return 0; 398575a0ae9SChristian Brauner } 399575a0ae9SChristian Brauner 400*740378dcSJoel Fernandes (Google) static void *test_pidfd_poll_exec_thread(void *priv) 401*740378dcSJoel Fernandes (Google) { 402*740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n", 403*740378dcSJoel Fernandes (Google) getpid(), syscall(SYS_gettid)); 404*740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: doing exec of sleep\n"); 405*740378dcSJoel Fernandes (Google) 406*740378dcSJoel Fernandes (Google) execl("/bin/sleep", "sleep", str(CHILD_THREAD_MIN_WAIT), (char *)NULL); 407*740378dcSJoel Fernandes (Google) 408*740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", 409*740378dcSJoel Fernandes (Google) getpid(), syscall(SYS_gettid)); 410*740378dcSJoel Fernandes (Google) return NULL; 411*740378dcSJoel Fernandes (Google) } 412*740378dcSJoel Fernandes (Google) 413*740378dcSJoel Fernandes (Google) static void poll_pidfd(const char *test_name, int pidfd) 414*740378dcSJoel Fernandes (Google) { 415*740378dcSJoel Fernandes (Google) int c; 416*740378dcSJoel Fernandes (Google) int epoll_fd = epoll_create1(EPOLL_CLOEXEC); 417*740378dcSJoel Fernandes (Google) struct epoll_event event, events[MAX_EVENTS]; 418*740378dcSJoel Fernandes (Google) 419*740378dcSJoel Fernandes (Google) if (epoll_fd == -1) 420*740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor " 421*740378dcSJoel Fernandes (Google) "(errno %d)\n", 422*740378dcSJoel Fernandes (Google) test_name, errno); 423*740378dcSJoel Fernandes (Google) 424*740378dcSJoel Fernandes (Google) event.events = EPOLLIN; 425*740378dcSJoel Fernandes (Google) event.data.fd = pidfd; 426*740378dcSJoel Fernandes (Google) 427*740378dcSJoel Fernandes (Google) if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) { 428*740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: Failed to add epoll file descriptor " 429*740378dcSJoel Fernandes (Google) "(errno %d)\n", 430*740378dcSJoel Fernandes (Google) test_name, errno); 431*740378dcSJoel Fernandes (Google) } 432*740378dcSJoel Fernandes (Google) 433*740378dcSJoel Fernandes (Google) c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000); 434*740378dcSJoel Fernandes (Google) if (c != 1 || !(events[0].events & EPOLLIN)) 435*740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x) ", 436*740378dcSJoel Fernandes (Google) "(errno %d)\n", 437*740378dcSJoel Fernandes (Google) test_name, c, events[0].events, errno); 438*740378dcSJoel Fernandes (Google) 439*740378dcSJoel Fernandes (Google) close(epoll_fd); 440*740378dcSJoel Fernandes (Google) return; 441*740378dcSJoel Fernandes (Google) 442*740378dcSJoel Fernandes (Google) } 443*740378dcSJoel Fernandes (Google) 444*740378dcSJoel Fernandes (Google) static int child_poll_exec_test(void *args) 445*740378dcSJoel Fernandes (Google) { 446*740378dcSJoel Fernandes (Google) pthread_t t1; 447*740378dcSJoel Fernandes (Google) 448*740378dcSJoel Fernandes (Google) ksft_print_msg("Child (pidfd): starting. pid %d tid %d\n", getpid(), 449*740378dcSJoel Fernandes (Google) syscall(SYS_gettid)); 450*740378dcSJoel Fernandes (Google) pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL); 451*740378dcSJoel Fernandes (Google) /* 452*740378dcSJoel Fernandes (Google) * Exec in the non-leader thread will destroy the leader immediately. 453*740378dcSJoel Fernandes (Google) * If the wait in the parent returns too soon, the test fails. 454*740378dcSJoel Fernandes (Google) */ 455*740378dcSJoel Fernandes (Google) while (1) 456*740378dcSJoel Fernandes (Google) sleep(1); 457*740378dcSJoel Fernandes (Google) } 458*740378dcSJoel Fernandes (Google) 459*740378dcSJoel Fernandes (Google) static void test_pidfd_poll_exec(int use_waitpid) 460*740378dcSJoel Fernandes (Google) { 461*740378dcSJoel Fernandes (Google) int pid, pidfd = 0; 462*740378dcSJoel Fernandes (Google) int status, ret; 463*740378dcSJoel Fernandes (Google) pthread_t t1; 464*740378dcSJoel Fernandes (Google) time_t prog_start = time(NULL); 465*740378dcSJoel Fernandes (Google) const char *test_name = "pidfd_poll check for premature notification on child thread exec"; 466*740378dcSJoel Fernandes (Google) 467*740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: pid: %d\n", getpid()); 468*740378dcSJoel Fernandes (Google) pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test); 469*740378dcSJoel Fernandes (Google) if (pid < 0) 470*740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n", 471*740378dcSJoel Fernandes (Google) test_name, pid, errno); 472*740378dcSJoel Fernandes (Google) 473*740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); 474*740378dcSJoel Fernandes (Google) 475*740378dcSJoel Fernandes (Google) if (use_waitpid) { 476*740378dcSJoel Fernandes (Google) ret = waitpid(pid, &status, 0); 477*740378dcSJoel Fernandes (Google) if (ret == -1) 478*740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: error\n"); 479*740378dcSJoel Fernandes (Google) 480*740378dcSJoel Fernandes (Google) if (ret == pid) 481*740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: Child process waited for.\n"); 482*740378dcSJoel Fernandes (Google) } else { 483*740378dcSJoel Fernandes (Google) poll_pidfd(test_name, pidfd); 484*740378dcSJoel Fernandes (Google) } 485*740378dcSJoel Fernandes (Google) 486*740378dcSJoel Fernandes (Google) time_t prog_time = time(NULL) - prog_start; 487*740378dcSJoel Fernandes (Google) 488*740378dcSJoel Fernandes (Google) ksft_print_msg("Time waited for child: %lu\n", prog_time); 489*740378dcSJoel Fernandes (Google) 490*740378dcSJoel Fernandes (Google) close(pidfd); 491*740378dcSJoel Fernandes (Google) 492*740378dcSJoel Fernandes (Google) if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2) 493*740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: Failed\n", test_name); 494*740378dcSJoel Fernandes (Google) else 495*740378dcSJoel Fernandes (Google) ksft_test_result_pass("%s test: Passed\n", test_name); 496*740378dcSJoel Fernandes (Google) } 497*740378dcSJoel Fernandes (Google) 498*740378dcSJoel Fernandes (Google) static void *test_pidfd_poll_leader_exit_thread(void *priv) 499*740378dcSJoel Fernandes (Google) { 500*740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n", 501*740378dcSJoel Fernandes (Google) getpid(), syscall(SYS_gettid)); 502*740378dcSJoel Fernandes (Google) sleep(CHILD_THREAD_MIN_WAIT); 503*740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", getpid(), syscall(SYS_gettid)); 504*740378dcSJoel Fernandes (Google) return NULL; 505*740378dcSJoel Fernandes (Google) } 506*740378dcSJoel Fernandes (Google) 507*740378dcSJoel Fernandes (Google) static time_t *child_exit_secs; 508*740378dcSJoel Fernandes (Google) static int child_poll_leader_exit_test(void *args) 509*740378dcSJoel Fernandes (Google) { 510*740378dcSJoel Fernandes (Google) pthread_t t1, t2; 511*740378dcSJoel Fernandes (Google) 512*740378dcSJoel Fernandes (Google) ksft_print_msg("Child: starting. pid %d tid %d\n", getpid(), syscall(SYS_gettid)); 513*740378dcSJoel Fernandes (Google) pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL); 514*740378dcSJoel Fernandes (Google) pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL); 515*740378dcSJoel Fernandes (Google) 516*740378dcSJoel Fernandes (Google) /* 517*740378dcSJoel Fernandes (Google) * glibc exit calls exit_group syscall, so explicity call exit only 518*740378dcSJoel Fernandes (Google) * so that only the group leader exits, leaving the threads alone. 519*740378dcSJoel Fernandes (Google) */ 520*740378dcSJoel Fernandes (Google) *child_exit_secs = time(NULL); 521*740378dcSJoel Fernandes (Google) syscall(SYS_exit, 0); 522*740378dcSJoel Fernandes (Google) } 523*740378dcSJoel Fernandes (Google) 524*740378dcSJoel Fernandes (Google) static void test_pidfd_poll_leader_exit(int use_waitpid) 525*740378dcSJoel Fernandes (Google) { 526*740378dcSJoel Fernandes (Google) int pid, pidfd = 0; 527*740378dcSJoel Fernandes (Google) int status, ret; 528*740378dcSJoel Fernandes (Google) time_t prog_start = time(NULL); 529*740378dcSJoel Fernandes (Google) const char *test_name = "pidfd_poll check for premature notification on non-empty" 530*740378dcSJoel Fernandes (Google) "group leader exit"; 531*740378dcSJoel Fernandes (Google) 532*740378dcSJoel Fernandes (Google) child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE, 533*740378dcSJoel Fernandes (Google) MAP_SHARED | MAP_ANONYMOUS, -1, 0); 534*740378dcSJoel Fernandes (Google) 535*740378dcSJoel Fernandes (Google) if (child_exit_secs == MAP_FAILED) 536*740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: mmap failed (errno %d)\n", 537*740378dcSJoel Fernandes (Google) test_name, errno); 538*740378dcSJoel Fernandes (Google) 539*740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: pid: %d\n", getpid()); 540*740378dcSJoel Fernandes (Google) pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test); 541*740378dcSJoel Fernandes (Google) if (pid < 0) 542*740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n", 543*740378dcSJoel Fernandes (Google) test_name, pid, errno); 544*740378dcSJoel Fernandes (Google) 545*740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); 546*740378dcSJoel Fernandes (Google) 547*740378dcSJoel Fernandes (Google) if (use_waitpid) { 548*740378dcSJoel Fernandes (Google) ret = waitpid(pid, &status, 0); 549*740378dcSJoel Fernandes (Google) if (ret == -1) 550*740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: error\n"); 551*740378dcSJoel Fernandes (Google) } else { 552*740378dcSJoel Fernandes (Google) /* 553*740378dcSJoel Fernandes (Google) * This sleep tests for the case where if the child exits, and is in 554*740378dcSJoel Fernandes (Google) * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll 555*740378dcSJoel Fernandes (Google) * doesn't prematurely return even though there are active threads 556*740378dcSJoel Fernandes (Google) */ 557*740378dcSJoel Fernandes (Google) sleep(1); 558*740378dcSJoel Fernandes (Google) poll_pidfd(test_name, pidfd); 559*740378dcSJoel Fernandes (Google) } 560*740378dcSJoel Fernandes (Google) 561*740378dcSJoel Fernandes (Google) if (ret == pid) 562*740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: Child process waited for.\n"); 563*740378dcSJoel Fernandes (Google) 564*740378dcSJoel Fernandes (Google) time_t since_child_exit = time(NULL) - *child_exit_secs; 565*740378dcSJoel Fernandes (Google) 566*740378dcSJoel Fernandes (Google) ksft_print_msg("Time since child exit: %lu\n", since_child_exit); 567*740378dcSJoel Fernandes (Google) 568*740378dcSJoel Fernandes (Google) close(pidfd); 569*740378dcSJoel Fernandes (Google) 570*740378dcSJoel Fernandes (Google) if (since_child_exit < CHILD_THREAD_MIN_WAIT || 571*740378dcSJoel Fernandes (Google) since_child_exit > CHILD_THREAD_MIN_WAIT + 2) 572*740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: Failed\n", test_name); 573*740378dcSJoel Fernandes (Google) else 574*740378dcSJoel Fernandes (Google) ksft_test_result_pass("%s test: Passed\n", test_name); 575*740378dcSJoel Fernandes (Google) } 576*740378dcSJoel Fernandes (Google) 577575a0ae9SChristian Brauner int main(int argc, char **argv) 578575a0ae9SChristian Brauner { 579575a0ae9SChristian Brauner ksft_print_header(); 5805821ba96SKees Cook ksft_set_plan(4); 581575a0ae9SChristian Brauner 582*740378dcSJoel Fernandes (Google) test_pidfd_poll_exec(0); 583*740378dcSJoel Fernandes (Google) test_pidfd_poll_exec(1); 584*740378dcSJoel Fernandes (Google) test_pidfd_poll_leader_exit(0); 585*740378dcSJoel Fernandes (Google) test_pidfd_poll_leader_exit(1); 586575a0ae9SChristian Brauner test_pidfd_send_signal_syscall_support(); 587575a0ae9SChristian Brauner test_pidfd_send_signal_simple_success(); 588575a0ae9SChristian Brauner test_pidfd_send_signal_exited_fail(); 589575a0ae9SChristian Brauner test_pidfd_send_signal_recycled_pid_fail(); 590575a0ae9SChristian Brauner 591575a0ae9SChristian Brauner return ksft_exit_pass(); 592575a0ae9SChristian Brauner } 593