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> 7740378dcSJoel 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> 14740378dcSJoel Fernandes (Google) #include <sys/epoll.h> 15740378dcSJoel Fernandes (Google) #include <sys/mman.h> 16575a0ae9SChristian Brauner #include <sys/mount.h> 17575a0ae9SChristian Brauner #include <sys/wait.h> 18740378dcSJoel Fernandes (Google) #include <time.h> 19575a0ae9SChristian Brauner #include <unistd.h> 20575a0ae9SChristian Brauner 21*172bb24aSChristian Brauner #include "pidfd.h" 22575a0ae9SChristian Brauner #include "../kselftest.h" 23575a0ae9SChristian Brauner 24*172bb24aSChristian Brauner #ifndef __NR_pidfd_send_signal 25*172bb24aSChristian Brauner #define __NR_pidfd_send_signal -1 26*172bb24aSChristian Brauner #endif 27*172bb24aSChristian Brauner 28740378dcSJoel Fernandes (Google) #define str(s) _str(s) 29740378dcSJoel Fernandes (Google) #define _str(s) #s 30740378dcSJoel Fernandes (Google) #define CHILD_THREAD_MIN_WAIT 3 /* seconds */ 31740378dcSJoel Fernandes (Google) 32740378dcSJoel Fernandes (Google) #define MAX_EVENTS 5 33740378dcSJoel Fernandes (Google) 34740378dcSJoel Fernandes (Google) #ifndef CLONE_PIDFD 35740378dcSJoel Fernandes (Google) #define CLONE_PIDFD 0x00001000 36740378dcSJoel Fernandes (Google) #endif 37740378dcSJoel Fernandes (Google) 38740378dcSJoel Fernandes (Google) static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *)) 39740378dcSJoel Fernandes (Google) { 40740378dcSJoel Fernandes (Google) size_t stack_size = 1024; 41740378dcSJoel Fernandes (Google) char *stack[1024] = { 0 }; 42740378dcSJoel Fernandes (Google) 43740378dcSJoel Fernandes (Google) #ifdef __ia64__ 44740378dcSJoel Fernandes (Google) return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd); 45740378dcSJoel Fernandes (Google) #else 46740378dcSJoel Fernandes (Google) return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd); 47740378dcSJoel Fernandes (Google) #endif 48740378dcSJoel Fernandes (Google) } 49740378dcSJoel Fernandes (Google) 50575a0ae9SChristian Brauner static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, 51575a0ae9SChristian Brauner unsigned int flags) 52575a0ae9SChristian Brauner { 53575a0ae9SChristian Brauner return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); 54575a0ae9SChristian Brauner } 55575a0ae9SChristian Brauner 56575a0ae9SChristian Brauner static int signal_received; 57575a0ae9SChristian Brauner 58575a0ae9SChristian Brauner static void set_signal_received_on_sigusr1(int sig) 59575a0ae9SChristian Brauner { 60575a0ae9SChristian Brauner if (sig == SIGUSR1) 61575a0ae9SChristian Brauner signal_received = 1; 62575a0ae9SChristian Brauner } 63575a0ae9SChristian Brauner 64575a0ae9SChristian Brauner /* 65575a0ae9SChristian Brauner * Straightforward test to see whether pidfd_send_signal() works is to send 66575a0ae9SChristian Brauner * a signal to ourself. 67575a0ae9SChristian Brauner */ 68575a0ae9SChristian Brauner static int test_pidfd_send_signal_simple_success(void) 69575a0ae9SChristian Brauner { 70575a0ae9SChristian Brauner int pidfd, ret; 71575a0ae9SChristian Brauner const char *test_name = "pidfd_send_signal send SIGUSR1"; 72575a0ae9SChristian Brauner 73575a0ae9SChristian Brauner pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC); 74575a0ae9SChristian Brauner if (pidfd < 0) 75575a0ae9SChristian Brauner ksft_exit_fail_msg( 76575a0ae9SChristian Brauner "%s test: Failed to open process file descriptor\n", 77575a0ae9SChristian Brauner test_name); 78575a0ae9SChristian Brauner 79575a0ae9SChristian Brauner signal(SIGUSR1, set_signal_received_on_sigusr1); 80575a0ae9SChristian Brauner 81575a0ae9SChristian Brauner ret = sys_pidfd_send_signal(pidfd, SIGUSR1, NULL, 0); 82575a0ae9SChristian Brauner close(pidfd); 83575a0ae9SChristian Brauner if (ret < 0) 84575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to send signal\n", 85575a0ae9SChristian Brauner test_name); 86575a0ae9SChristian Brauner 87575a0ae9SChristian Brauner if (signal_received != 1) 88575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to receive signal\n", 89575a0ae9SChristian Brauner test_name); 90575a0ae9SChristian Brauner 91575a0ae9SChristian Brauner signal_received = 0; 92575a0ae9SChristian Brauner ksft_test_result_pass("%s test: Sent signal\n", test_name); 93575a0ae9SChristian Brauner return 0; 94575a0ae9SChristian Brauner } 95575a0ae9SChristian Brauner 96575a0ae9SChristian Brauner static int test_pidfd_send_signal_exited_fail(void) 97575a0ae9SChristian Brauner { 98575a0ae9SChristian Brauner int pidfd, ret, saved_errno; 99575a0ae9SChristian Brauner char buf[256]; 100575a0ae9SChristian Brauner pid_t pid; 101575a0ae9SChristian Brauner const char *test_name = "pidfd_send_signal signal exited process"; 102575a0ae9SChristian Brauner 103575a0ae9SChristian Brauner pid = fork(); 104575a0ae9SChristian Brauner if (pid < 0) 105575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to create new process\n", 106575a0ae9SChristian Brauner test_name); 107575a0ae9SChristian Brauner 108575a0ae9SChristian Brauner if (pid == 0) 109575a0ae9SChristian Brauner _exit(EXIT_SUCCESS); 110575a0ae9SChristian Brauner 111575a0ae9SChristian Brauner snprintf(buf, sizeof(buf), "/proc/%d", pid); 112575a0ae9SChristian Brauner 113575a0ae9SChristian Brauner pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); 114575a0ae9SChristian Brauner 115575a0ae9SChristian Brauner (void)wait_for_pid(pid); 116575a0ae9SChristian Brauner 117575a0ae9SChristian Brauner if (pidfd < 0) 118575a0ae9SChristian Brauner ksft_exit_fail_msg( 119575a0ae9SChristian Brauner "%s test: Failed to open process file descriptor\n", 120575a0ae9SChristian Brauner test_name); 121575a0ae9SChristian Brauner 122575a0ae9SChristian Brauner ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); 123575a0ae9SChristian Brauner saved_errno = errno; 124575a0ae9SChristian Brauner close(pidfd); 125575a0ae9SChristian Brauner if (ret == 0) 126575a0ae9SChristian Brauner ksft_exit_fail_msg( 127575a0ae9SChristian Brauner "%s test: Managed to send signal to process even though it should have failed\n", 128575a0ae9SChristian Brauner test_name); 129575a0ae9SChristian Brauner 130575a0ae9SChristian Brauner if (saved_errno != ESRCH) 131575a0ae9SChristian Brauner ksft_exit_fail_msg( 132575a0ae9SChristian Brauner "%s test: Expected to receive ESRCH as errno value but received %d instead\n", 133575a0ae9SChristian Brauner test_name, saved_errno); 134575a0ae9SChristian Brauner 135575a0ae9SChristian Brauner ksft_test_result_pass("%s test: Failed to send signal as expected\n", 136575a0ae9SChristian Brauner test_name); 137575a0ae9SChristian Brauner return 0; 138575a0ae9SChristian Brauner } 139575a0ae9SChristian Brauner 140575a0ae9SChristian Brauner /* 141575a0ae9SChristian Brauner * Maximum number of cycles we allow. This is equivalent to PID_MAX_DEFAULT. 142575a0ae9SChristian Brauner * If users set a higher limit or we have cycled PIDFD_MAX_DEFAULT number of 143575a0ae9SChristian Brauner * times then we skip the test to not go into an infinite loop or block for a 144575a0ae9SChristian Brauner * long time. 145575a0ae9SChristian Brauner */ 146575a0ae9SChristian Brauner #define PIDFD_MAX_DEFAULT 0x8000 147575a0ae9SChristian Brauner 148575a0ae9SChristian Brauner static int test_pidfd_send_signal_recycled_pid_fail(void) 149575a0ae9SChristian Brauner { 150575a0ae9SChristian Brauner int i, ret; 151575a0ae9SChristian Brauner pid_t pid1; 152575a0ae9SChristian Brauner const char *test_name = "pidfd_send_signal signal recycled pid"; 153575a0ae9SChristian Brauner 154575a0ae9SChristian Brauner ret = unshare(CLONE_NEWPID); 155575a0ae9SChristian Brauner if (ret < 0) 156575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to unshare pid namespace\n", 157575a0ae9SChristian Brauner test_name); 158575a0ae9SChristian Brauner 159575a0ae9SChristian Brauner ret = unshare(CLONE_NEWNS); 160575a0ae9SChristian Brauner if (ret < 0) 161575a0ae9SChristian Brauner ksft_exit_fail_msg( 162575a0ae9SChristian Brauner "%s test: Failed to unshare mount namespace\n", 163575a0ae9SChristian Brauner test_name); 164575a0ae9SChristian Brauner 165575a0ae9SChristian Brauner ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0); 166575a0ae9SChristian Brauner if (ret < 0) 167575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to remount / private\n", 168575a0ae9SChristian Brauner test_name); 169575a0ae9SChristian Brauner 170575a0ae9SChristian Brauner /* pid 1 in new pid namespace */ 171575a0ae9SChristian Brauner pid1 = fork(); 172575a0ae9SChristian Brauner if (pid1 < 0) 173575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to create new process\n", 174575a0ae9SChristian Brauner test_name); 175575a0ae9SChristian Brauner 176575a0ae9SChristian Brauner if (pid1 == 0) { 177575a0ae9SChristian Brauner char buf[256]; 178575a0ae9SChristian Brauner pid_t pid2; 179575a0ae9SChristian Brauner int pidfd = -1; 180575a0ae9SChristian Brauner 181575a0ae9SChristian Brauner (void)umount2("/proc", MNT_DETACH); 182575a0ae9SChristian Brauner ret = mount("proc", "/proc", "proc", 0, NULL); 183575a0ae9SChristian Brauner if (ret < 0) 184575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 185575a0ae9SChristian Brauner 186575a0ae9SChristian Brauner /* grab pid PID_RECYCLE */ 187575a0ae9SChristian Brauner for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) { 188575a0ae9SChristian Brauner pid2 = fork(); 189575a0ae9SChristian Brauner if (pid2 < 0) 190575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 191575a0ae9SChristian Brauner 192575a0ae9SChristian Brauner if (pid2 == 0) 193575a0ae9SChristian Brauner _exit(PIDFD_PASS); 194575a0ae9SChristian Brauner 195575a0ae9SChristian Brauner if (pid2 == PID_RECYCLE) { 196575a0ae9SChristian Brauner snprintf(buf, sizeof(buf), "/proc/%d", pid2); 197575a0ae9SChristian Brauner ksft_print_msg("pid to recycle is %d\n", pid2); 198575a0ae9SChristian Brauner pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); 199575a0ae9SChristian Brauner } 200575a0ae9SChristian Brauner 201575a0ae9SChristian Brauner if (wait_for_pid(pid2)) 202575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 203575a0ae9SChristian Brauner 204575a0ae9SChristian Brauner if (pid2 >= PID_RECYCLE) 205575a0ae9SChristian Brauner break; 206575a0ae9SChristian Brauner } 207575a0ae9SChristian Brauner 208575a0ae9SChristian Brauner /* 209575a0ae9SChristian Brauner * We want to be as predictable as we can so if we haven't been 210575a0ae9SChristian Brauner * able to grab pid PID_RECYCLE skip the test. 211575a0ae9SChristian Brauner */ 212575a0ae9SChristian Brauner if (pid2 != PID_RECYCLE) { 213575a0ae9SChristian Brauner /* skip test */ 214575a0ae9SChristian Brauner close(pidfd); 215575a0ae9SChristian Brauner _exit(PIDFD_SKIP); 216575a0ae9SChristian Brauner } 217575a0ae9SChristian Brauner 218575a0ae9SChristian Brauner if (pidfd < 0) 219575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 220575a0ae9SChristian Brauner 221575a0ae9SChristian Brauner for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) { 222575a0ae9SChristian Brauner char c; 223575a0ae9SChristian Brauner int pipe_fds[2]; 224575a0ae9SChristian Brauner pid_t recycled_pid; 225575a0ae9SChristian Brauner int child_ret = PIDFD_PASS; 226575a0ae9SChristian Brauner 227575a0ae9SChristian Brauner ret = pipe2(pipe_fds, O_CLOEXEC); 228575a0ae9SChristian Brauner if (ret < 0) 229575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 230575a0ae9SChristian Brauner 231575a0ae9SChristian Brauner recycled_pid = fork(); 232575a0ae9SChristian Brauner if (recycled_pid < 0) 233575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 234575a0ae9SChristian Brauner 235575a0ae9SChristian Brauner if (recycled_pid == 0) { 236575a0ae9SChristian Brauner close(pipe_fds[1]); 237575a0ae9SChristian Brauner (void)read(pipe_fds[0], &c, 1); 238575a0ae9SChristian Brauner close(pipe_fds[0]); 239575a0ae9SChristian Brauner 240575a0ae9SChristian Brauner _exit(PIDFD_PASS); 241575a0ae9SChristian Brauner } 242575a0ae9SChristian Brauner 243575a0ae9SChristian Brauner /* 244575a0ae9SChristian Brauner * Stop the child so we can inspect whether we have 245575a0ae9SChristian Brauner * recycled pid PID_RECYCLE. 246575a0ae9SChristian Brauner */ 247575a0ae9SChristian Brauner close(pipe_fds[0]); 248575a0ae9SChristian Brauner ret = kill(recycled_pid, SIGSTOP); 249575a0ae9SChristian Brauner close(pipe_fds[1]); 250575a0ae9SChristian Brauner if (ret) { 251575a0ae9SChristian Brauner (void)wait_for_pid(recycled_pid); 252575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 253575a0ae9SChristian Brauner } 254575a0ae9SChristian Brauner 255575a0ae9SChristian Brauner /* 256575a0ae9SChristian Brauner * We have recycled the pid. Try to signal it. This 257575a0ae9SChristian Brauner * needs to fail since this is a different process than 258575a0ae9SChristian Brauner * the one the pidfd refers to. 259575a0ae9SChristian Brauner */ 260575a0ae9SChristian Brauner if (recycled_pid == PID_RECYCLE) { 261575a0ae9SChristian Brauner ret = sys_pidfd_send_signal(pidfd, SIGCONT, 262575a0ae9SChristian Brauner NULL, 0); 263575a0ae9SChristian Brauner if (ret && errno == ESRCH) 264575a0ae9SChristian Brauner child_ret = PIDFD_XFAIL; 265575a0ae9SChristian Brauner else 266575a0ae9SChristian Brauner child_ret = PIDFD_FAIL; 267575a0ae9SChristian Brauner } 268575a0ae9SChristian Brauner 269575a0ae9SChristian Brauner /* let the process move on */ 270575a0ae9SChristian Brauner ret = kill(recycled_pid, SIGCONT); 271575a0ae9SChristian Brauner if (ret) 272575a0ae9SChristian Brauner (void)kill(recycled_pid, SIGKILL); 273575a0ae9SChristian Brauner 274575a0ae9SChristian Brauner if (wait_for_pid(recycled_pid)) 275575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 276575a0ae9SChristian Brauner 277575a0ae9SChristian Brauner switch (child_ret) { 278575a0ae9SChristian Brauner case PIDFD_FAIL: 279575a0ae9SChristian Brauner /* fallthrough */ 280575a0ae9SChristian Brauner case PIDFD_XFAIL: 281575a0ae9SChristian Brauner _exit(child_ret); 282575a0ae9SChristian Brauner case PIDFD_PASS: 283575a0ae9SChristian Brauner break; 284575a0ae9SChristian Brauner default: 285575a0ae9SChristian Brauner /* not reached */ 286575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 287575a0ae9SChristian Brauner } 288575a0ae9SChristian Brauner 289575a0ae9SChristian Brauner /* 290575a0ae9SChristian Brauner * If the user set a custom pid_max limit we could be 291575a0ae9SChristian Brauner * in the millions. 292575a0ae9SChristian Brauner * Skip the test in this case. 293575a0ae9SChristian Brauner */ 294575a0ae9SChristian Brauner if (recycled_pid > PIDFD_MAX_DEFAULT) 295575a0ae9SChristian Brauner _exit(PIDFD_SKIP); 296575a0ae9SChristian Brauner } 297575a0ae9SChristian Brauner 298575a0ae9SChristian Brauner /* failed to recycle pid */ 299575a0ae9SChristian Brauner _exit(PIDFD_SKIP); 300575a0ae9SChristian Brauner } 301575a0ae9SChristian Brauner 302575a0ae9SChristian Brauner ret = wait_for_pid(pid1); 303575a0ae9SChristian Brauner switch (ret) { 304575a0ae9SChristian Brauner case PIDFD_FAIL: 305575a0ae9SChristian Brauner ksft_exit_fail_msg( 306575a0ae9SChristian Brauner "%s test: Managed to signal recycled pid %d\n", 307575a0ae9SChristian Brauner test_name, PID_RECYCLE); 308575a0ae9SChristian Brauner case PIDFD_PASS: 309575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to recycle pid %d\n", 310575a0ae9SChristian Brauner test_name, PID_RECYCLE); 311575a0ae9SChristian Brauner case PIDFD_SKIP: 312575a0ae9SChristian Brauner ksft_print_msg("%s test: Skipping test\n", test_name); 313575a0ae9SChristian Brauner ret = 0; 314575a0ae9SChristian Brauner break; 315575a0ae9SChristian Brauner case PIDFD_XFAIL: 316575a0ae9SChristian Brauner ksft_test_result_pass( 317575a0ae9SChristian Brauner "%s test: Failed to signal recycled pid as expected\n", 318575a0ae9SChristian Brauner test_name); 319575a0ae9SChristian Brauner ret = 0; 320575a0ae9SChristian Brauner break; 321575a0ae9SChristian Brauner default /* PIDFD_ERROR */: 322575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Error while running tests\n", 323575a0ae9SChristian Brauner test_name); 324575a0ae9SChristian Brauner } 325575a0ae9SChristian Brauner 326575a0ae9SChristian Brauner return ret; 327575a0ae9SChristian Brauner } 328575a0ae9SChristian Brauner 329575a0ae9SChristian Brauner static int test_pidfd_send_signal_syscall_support(void) 330575a0ae9SChristian Brauner { 331575a0ae9SChristian Brauner int pidfd, ret; 332575a0ae9SChristian Brauner const char *test_name = "pidfd_send_signal check for support"; 333575a0ae9SChristian Brauner 334575a0ae9SChristian Brauner pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC); 335575a0ae9SChristian Brauner if (pidfd < 0) 336575a0ae9SChristian Brauner ksft_exit_fail_msg( 337575a0ae9SChristian Brauner "%s test: Failed to open process file descriptor\n", 338575a0ae9SChristian Brauner test_name); 339575a0ae9SChristian Brauner 340575a0ae9SChristian Brauner ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); 341575a0ae9SChristian Brauner if (ret < 0) { 342575a0ae9SChristian Brauner /* 343575a0ae9SChristian Brauner * pidfd_send_signal() will currently return ENOSYS when 344575a0ae9SChristian Brauner * CONFIG_PROC_FS is not set. 345575a0ae9SChristian Brauner */ 346575a0ae9SChristian Brauner if (errno == ENOSYS) 347575a0ae9SChristian Brauner ksft_exit_skip( 348575a0ae9SChristian Brauner "%s test: pidfd_send_signal() syscall not supported (Ensure that CONFIG_PROC_FS=y is set)\n", 349575a0ae9SChristian Brauner test_name); 350575a0ae9SChristian Brauner 351575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to send signal\n", 352575a0ae9SChristian Brauner test_name); 353575a0ae9SChristian Brauner } 354575a0ae9SChristian Brauner 355575a0ae9SChristian Brauner close(pidfd); 356575a0ae9SChristian Brauner ksft_test_result_pass( 357575a0ae9SChristian Brauner "%s test: pidfd_send_signal() syscall is supported. Tests can be executed\n", 358575a0ae9SChristian Brauner test_name); 359575a0ae9SChristian Brauner return 0; 360575a0ae9SChristian Brauner } 361575a0ae9SChristian Brauner 362740378dcSJoel Fernandes (Google) static void *test_pidfd_poll_exec_thread(void *priv) 363740378dcSJoel Fernandes (Google) { 364740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n", 365740378dcSJoel Fernandes (Google) getpid(), syscall(SYS_gettid)); 366740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: doing exec of sleep\n"); 367740378dcSJoel Fernandes (Google) 368740378dcSJoel Fernandes (Google) execl("/bin/sleep", "sleep", str(CHILD_THREAD_MIN_WAIT), (char *)NULL); 369740378dcSJoel Fernandes (Google) 370740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", 371740378dcSJoel Fernandes (Google) getpid(), syscall(SYS_gettid)); 372740378dcSJoel Fernandes (Google) return NULL; 373740378dcSJoel Fernandes (Google) } 374740378dcSJoel Fernandes (Google) 375740378dcSJoel Fernandes (Google) static void poll_pidfd(const char *test_name, int pidfd) 376740378dcSJoel Fernandes (Google) { 377740378dcSJoel Fernandes (Google) int c; 378740378dcSJoel Fernandes (Google) int epoll_fd = epoll_create1(EPOLL_CLOEXEC); 379740378dcSJoel Fernandes (Google) struct epoll_event event, events[MAX_EVENTS]; 380740378dcSJoel Fernandes (Google) 381740378dcSJoel Fernandes (Google) if (epoll_fd == -1) 382740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor " 383740378dcSJoel Fernandes (Google) "(errno %d)\n", 384740378dcSJoel Fernandes (Google) test_name, errno); 385740378dcSJoel Fernandes (Google) 386740378dcSJoel Fernandes (Google) event.events = EPOLLIN; 387740378dcSJoel Fernandes (Google) event.data.fd = pidfd; 388740378dcSJoel Fernandes (Google) 389740378dcSJoel Fernandes (Google) if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) { 390740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: Failed to add epoll file descriptor " 391740378dcSJoel Fernandes (Google) "(errno %d)\n", 392740378dcSJoel Fernandes (Google) test_name, errno); 393740378dcSJoel Fernandes (Google) } 394740378dcSJoel Fernandes (Google) 395740378dcSJoel Fernandes (Google) c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000); 396740378dcSJoel Fernandes (Google) if (c != 1 || !(events[0].events & EPOLLIN)) 397740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x) ", 398740378dcSJoel Fernandes (Google) "(errno %d)\n", 399740378dcSJoel Fernandes (Google) test_name, c, events[0].events, errno); 400740378dcSJoel Fernandes (Google) 401740378dcSJoel Fernandes (Google) close(epoll_fd); 402740378dcSJoel Fernandes (Google) return; 403740378dcSJoel Fernandes (Google) 404740378dcSJoel Fernandes (Google) } 405740378dcSJoel Fernandes (Google) 406740378dcSJoel Fernandes (Google) static int child_poll_exec_test(void *args) 407740378dcSJoel Fernandes (Google) { 408740378dcSJoel Fernandes (Google) pthread_t t1; 409740378dcSJoel Fernandes (Google) 410740378dcSJoel Fernandes (Google) ksft_print_msg("Child (pidfd): starting. pid %d tid %d\n", getpid(), 411740378dcSJoel Fernandes (Google) syscall(SYS_gettid)); 412740378dcSJoel Fernandes (Google) pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL); 413740378dcSJoel Fernandes (Google) /* 414740378dcSJoel Fernandes (Google) * Exec in the non-leader thread will destroy the leader immediately. 415740378dcSJoel Fernandes (Google) * If the wait in the parent returns too soon, the test fails. 416740378dcSJoel Fernandes (Google) */ 417740378dcSJoel Fernandes (Google) while (1) 418740378dcSJoel Fernandes (Google) sleep(1); 419740378dcSJoel Fernandes (Google) } 420740378dcSJoel Fernandes (Google) 421740378dcSJoel Fernandes (Google) static void test_pidfd_poll_exec(int use_waitpid) 422740378dcSJoel Fernandes (Google) { 423740378dcSJoel Fernandes (Google) int pid, pidfd = 0; 424740378dcSJoel Fernandes (Google) int status, ret; 425740378dcSJoel Fernandes (Google) pthread_t t1; 426740378dcSJoel Fernandes (Google) time_t prog_start = time(NULL); 427740378dcSJoel Fernandes (Google) const char *test_name = "pidfd_poll check for premature notification on child thread exec"; 428740378dcSJoel Fernandes (Google) 429740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: pid: %d\n", getpid()); 430740378dcSJoel Fernandes (Google) pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test); 431740378dcSJoel Fernandes (Google) if (pid < 0) 432740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n", 433740378dcSJoel Fernandes (Google) test_name, pid, errno); 434740378dcSJoel Fernandes (Google) 435740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); 436740378dcSJoel Fernandes (Google) 437740378dcSJoel Fernandes (Google) if (use_waitpid) { 438740378dcSJoel Fernandes (Google) ret = waitpid(pid, &status, 0); 439740378dcSJoel Fernandes (Google) if (ret == -1) 440740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: error\n"); 441740378dcSJoel Fernandes (Google) 442740378dcSJoel Fernandes (Google) if (ret == pid) 443740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: Child process waited for.\n"); 444740378dcSJoel Fernandes (Google) } else { 445740378dcSJoel Fernandes (Google) poll_pidfd(test_name, pidfd); 446740378dcSJoel Fernandes (Google) } 447740378dcSJoel Fernandes (Google) 448740378dcSJoel Fernandes (Google) time_t prog_time = time(NULL) - prog_start; 449740378dcSJoel Fernandes (Google) 450740378dcSJoel Fernandes (Google) ksft_print_msg("Time waited for child: %lu\n", prog_time); 451740378dcSJoel Fernandes (Google) 452740378dcSJoel Fernandes (Google) close(pidfd); 453740378dcSJoel Fernandes (Google) 454740378dcSJoel Fernandes (Google) if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2) 455740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: Failed\n", test_name); 456740378dcSJoel Fernandes (Google) else 457740378dcSJoel Fernandes (Google) ksft_test_result_pass("%s test: Passed\n", test_name); 458740378dcSJoel Fernandes (Google) } 459740378dcSJoel Fernandes (Google) 460740378dcSJoel Fernandes (Google) static void *test_pidfd_poll_leader_exit_thread(void *priv) 461740378dcSJoel Fernandes (Google) { 462740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n", 463740378dcSJoel Fernandes (Google) getpid(), syscall(SYS_gettid)); 464740378dcSJoel Fernandes (Google) sleep(CHILD_THREAD_MIN_WAIT); 465740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", getpid(), syscall(SYS_gettid)); 466740378dcSJoel Fernandes (Google) return NULL; 467740378dcSJoel Fernandes (Google) } 468740378dcSJoel Fernandes (Google) 469740378dcSJoel Fernandes (Google) static time_t *child_exit_secs; 470740378dcSJoel Fernandes (Google) static int child_poll_leader_exit_test(void *args) 471740378dcSJoel Fernandes (Google) { 472740378dcSJoel Fernandes (Google) pthread_t t1, t2; 473740378dcSJoel Fernandes (Google) 474740378dcSJoel Fernandes (Google) ksft_print_msg("Child: starting. pid %d tid %d\n", getpid(), syscall(SYS_gettid)); 475740378dcSJoel Fernandes (Google) pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL); 476740378dcSJoel Fernandes (Google) pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL); 477740378dcSJoel Fernandes (Google) 478740378dcSJoel Fernandes (Google) /* 479740378dcSJoel Fernandes (Google) * glibc exit calls exit_group syscall, so explicity call exit only 480740378dcSJoel Fernandes (Google) * so that only the group leader exits, leaving the threads alone. 481740378dcSJoel Fernandes (Google) */ 482740378dcSJoel Fernandes (Google) *child_exit_secs = time(NULL); 483740378dcSJoel Fernandes (Google) syscall(SYS_exit, 0); 484740378dcSJoel Fernandes (Google) } 485740378dcSJoel Fernandes (Google) 486740378dcSJoel Fernandes (Google) static void test_pidfd_poll_leader_exit(int use_waitpid) 487740378dcSJoel Fernandes (Google) { 488740378dcSJoel Fernandes (Google) int pid, pidfd = 0; 489740378dcSJoel Fernandes (Google) int status, ret; 490740378dcSJoel Fernandes (Google) time_t prog_start = time(NULL); 491740378dcSJoel Fernandes (Google) const char *test_name = "pidfd_poll check for premature notification on non-empty" 492740378dcSJoel Fernandes (Google) "group leader exit"; 493740378dcSJoel Fernandes (Google) 494740378dcSJoel Fernandes (Google) child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE, 495740378dcSJoel Fernandes (Google) MAP_SHARED | MAP_ANONYMOUS, -1, 0); 496740378dcSJoel Fernandes (Google) 497740378dcSJoel Fernandes (Google) if (child_exit_secs == MAP_FAILED) 498740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: mmap failed (errno %d)\n", 499740378dcSJoel Fernandes (Google) test_name, errno); 500740378dcSJoel Fernandes (Google) 501740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: pid: %d\n", getpid()); 502740378dcSJoel Fernandes (Google) pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test); 503740378dcSJoel Fernandes (Google) if (pid < 0) 504740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n", 505740378dcSJoel Fernandes (Google) test_name, pid, errno); 506740378dcSJoel Fernandes (Google) 507740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); 508740378dcSJoel Fernandes (Google) 509740378dcSJoel Fernandes (Google) if (use_waitpid) { 510740378dcSJoel Fernandes (Google) ret = waitpid(pid, &status, 0); 511740378dcSJoel Fernandes (Google) if (ret == -1) 512740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: error\n"); 513740378dcSJoel Fernandes (Google) } else { 514740378dcSJoel Fernandes (Google) /* 515740378dcSJoel Fernandes (Google) * This sleep tests for the case where if the child exits, and is in 516740378dcSJoel Fernandes (Google) * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll 517740378dcSJoel Fernandes (Google) * doesn't prematurely return even though there are active threads 518740378dcSJoel Fernandes (Google) */ 519740378dcSJoel Fernandes (Google) sleep(1); 520740378dcSJoel Fernandes (Google) poll_pidfd(test_name, pidfd); 521740378dcSJoel Fernandes (Google) } 522740378dcSJoel Fernandes (Google) 523740378dcSJoel Fernandes (Google) if (ret == pid) 524740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: Child process waited for.\n"); 525740378dcSJoel Fernandes (Google) 526740378dcSJoel Fernandes (Google) time_t since_child_exit = time(NULL) - *child_exit_secs; 527740378dcSJoel Fernandes (Google) 528740378dcSJoel Fernandes (Google) ksft_print_msg("Time since child exit: %lu\n", since_child_exit); 529740378dcSJoel Fernandes (Google) 530740378dcSJoel Fernandes (Google) close(pidfd); 531740378dcSJoel Fernandes (Google) 532740378dcSJoel Fernandes (Google) if (since_child_exit < CHILD_THREAD_MIN_WAIT || 533740378dcSJoel Fernandes (Google) since_child_exit > CHILD_THREAD_MIN_WAIT + 2) 534740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: Failed\n", test_name); 535740378dcSJoel Fernandes (Google) else 536740378dcSJoel Fernandes (Google) ksft_test_result_pass("%s test: Passed\n", test_name); 537740378dcSJoel Fernandes (Google) } 538740378dcSJoel Fernandes (Google) 539575a0ae9SChristian Brauner int main(int argc, char **argv) 540575a0ae9SChristian Brauner { 541575a0ae9SChristian Brauner ksft_print_header(); 5425821ba96SKees Cook ksft_set_plan(4); 543575a0ae9SChristian Brauner 544740378dcSJoel Fernandes (Google) test_pidfd_poll_exec(0); 545740378dcSJoel Fernandes (Google) test_pidfd_poll_exec(1); 546740378dcSJoel Fernandes (Google) test_pidfd_poll_leader_exit(0); 547740378dcSJoel Fernandes (Google) test_pidfd_poll_leader_exit(1); 548575a0ae9SChristian Brauner test_pidfd_send_signal_syscall_support(); 549575a0ae9SChristian Brauner test_pidfd_send_signal_simple_success(); 550575a0ae9SChristian Brauner test_pidfd_send_signal_exited_fail(); 551575a0ae9SChristian Brauner test_pidfd_send_signal_recycled_pid_fail(); 552575a0ae9SChristian Brauner 553575a0ae9SChristian Brauner return ksft_exit_pass(); 554575a0ae9SChristian Brauner } 555