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> 11bb91c0caSPaolo Bonzini #include <stdbool.h> 12575a0ae9SChristian Brauner #include <stdlib.h> 13575a0ae9SChristian Brauner #include <string.h> 14575a0ae9SChristian Brauner #include <syscall.h> 15740378dcSJoel Fernandes (Google) #include <sys/epoll.h> 16740378dcSJoel Fernandes (Google) #include <sys/mman.h> 17575a0ae9SChristian Brauner #include <sys/mount.h> 18575a0ae9SChristian Brauner #include <sys/wait.h> 19740378dcSJoel Fernandes (Google) #include <time.h> 20575a0ae9SChristian Brauner #include <unistd.h> 21575a0ae9SChristian Brauner 22172bb24aSChristian Brauner #include "pidfd.h" 23575a0ae9SChristian Brauner #include "../kselftest.h" 24575a0ae9SChristian Brauner 25740378dcSJoel Fernandes (Google) #define str(s) _str(s) 26740378dcSJoel Fernandes (Google) #define _str(s) #s 27740378dcSJoel Fernandes (Google) #define CHILD_THREAD_MIN_WAIT 3 /* seconds */ 28740378dcSJoel Fernandes (Google) 29740378dcSJoel Fernandes (Google) #define MAX_EVENTS 5 30740378dcSJoel Fernandes (Google) 31bb91c0caSPaolo Bonzini static bool have_pidfd_send_signal; 32bb91c0caSPaolo Bonzini 33740378dcSJoel Fernandes (Google) static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *)) 34740378dcSJoel Fernandes (Google) { 35740378dcSJoel Fernandes (Google) size_t stack_size = 1024; 36740378dcSJoel Fernandes (Google) char *stack[1024] = { 0 }; 37740378dcSJoel Fernandes (Google) 38740378dcSJoel Fernandes (Google) #ifdef __ia64__ 39740378dcSJoel Fernandes (Google) return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd); 40740378dcSJoel Fernandes (Google) #else 41740378dcSJoel Fernandes (Google) return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd); 42740378dcSJoel Fernandes (Google) #endif 43740378dcSJoel Fernandes (Google) } 44740378dcSJoel Fernandes (Google) 45575a0ae9SChristian Brauner static int signal_received; 46575a0ae9SChristian Brauner 47575a0ae9SChristian Brauner static void set_signal_received_on_sigusr1(int sig) 48575a0ae9SChristian Brauner { 49575a0ae9SChristian Brauner if (sig == SIGUSR1) 50575a0ae9SChristian Brauner signal_received = 1; 51575a0ae9SChristian Brauner } 52575a0ae9SChristian Brauner 53575a0ae9SChristian Brauner /* 54575a0ae9SChristian Brauner * Straightforward test to see whether pidfd_send_signal() works is to send 55575a0ae9SChristian Brauner * a signal to ourself. 56575a0ae9SChristian Brauner */ 57575a0ae9SChristian Brauner static int test_pidfd_send_signal_simple_success(void) 58575a0ae9SChristian Brauner { 59575a0ae9SChristian Brauner int pidfd, ret; 60575a0ae9SChristian Brauner const char *test_name = "pidfd_send_signal send SIGUSR1"; 61575a0ae9SChristian Brauner 62bb91c0caSPaolo Bonzini if (!have_pidfd_send_signal) { 63bb91c0caSPaolo Bonzini ksft_test_result_skip( 64bb91c0caSPaolo Bonzini "%s test: pidfd_send_signal() syscall not supported\n", 65bb91c0caSPaolo Bonzini test_name); 66bb91c0caSPaolo Bonzini return 0; 67bb91c0caSPaolo Bonzini } 68bb91c0caSPaolo Bonzini 69575a0ae9SChristian Brauner pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC); 70575a0ae9SChristian Brauner if (pidfd < 0) 71575a0ae9SChristian Brauner ksft_exit_fail_msg( 72575a0ae9SChristian Brauner "%s test: Failed to open process file descriptor\n", 73575a0ae9SChristian Brauner test_name); 74575a0ae9SChristian Brauner 75575a0ae9SChristian Brauner signal(SIGUSR1, set_signal_received_on_sigusr1); 76575a0ae9SChristian Brauner 77575a0ae9SChristian Brauner ret = sys_pidfd_send_signal(pidfd, SIGUSR1, NULL, 0); 78575a0ae9SChristian Brauner close(pidfd); 79575a0ae9SChristian Brauner if (ret < 0) 80575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to send signal\n", 81575a0ae9SChristian Brauner test_name); 82575a0ae9SChristian Brauner 83575a0ae9SChristian Brauner if (signal_received != 1) 84575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to receive signal\n", 85575a0ae9SChristian Brauner test_name); 86575a0ae9SChristian Brauner 87575a0ae9SChristian Brauner signal_received = 0; 88575a0ae9SChristian Brauner ksft_test_result_pass("%s test: Sent signal\n", test_name); 89575a0ae9SChristian Brauner return 0; 90575a0ae9SChristian Brauner } 91575a0ae9SChristian Brauner 92575a0ae9SChristian Brauner static int test_pidfd_send_signal_exited_fail(void) 93575a0ae9SChristian Brauner { 94575a0ae9SChristian Brauner int pidfd, ret, saved_errno; 95575a0ae9SChristian Brauner char buf[256]; 96575a0ae9SChristian Brauner pid_t pid; 97575a0ae9SChristian Brauner const char *test_name = "pidfd_send_signal signal exited process"; 98575a0ae9SChristian Brauner 99bb91c0caSPaolo Bonzini if (!have_pidfd_send_signal) { 100bb91c0caSPaolo Bonzini ksft_test_result_skip( 101bb91c0caSPaolo Bonzini "%s test: pidfd_send_signal() syscall not supported\n", 102bb91c0caSPaolo Bonzini test_name); 103bb91c0caSPaolo Bonzini return 0; 104bb91c0caSPaolo Bonzini } 105bb91c0caSPaolo Bonzini 106575a0ae9SChristian Brauner pid = fork(); 107575a0ae9SChristian Brauner if (pid < 0) 108575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to create new process\n", 109575a0ae9SChristian Brauner test_name); 110575a0ae9SChristian Brauner 111575a0ae9SChristian Brauner if (pid == 0) 112575a0ae9SChristian Brauner _exit(EXIT_SUCCESS); 113575a0ae9SChristian Brauner 114575a0ae9SChristian Brauner snprintf(buf, sizeof(buf), "/proc/%d", pid); 115575a0ae9SChristian Brauner 116575a0ae9SChristian Brauner pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); 117575a0ae9SChristian Brauner 118*bcda4c86SZiqi Zhao ret = wait_for_pid(pid); 119*bcda4c86SZiqi Zhao ksft_print_msg("waitpid WEXITSTATUS=%d\n", ret); 120575a0ae9SChristian Brauner 121575a0ae9SChristian Brauner if (pidfd < 0) 122575a0ae9SChristian Brauner ksft_exit_fail_msg( 123575a0ae9SChristian Brauner "%s test: Failed to open process file descriptor\n", 124575a0ae9SChristian Brauner test_name); 125575a0ae9SChristian Brauner 126575a0ae9SChristian Brauner ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); 127575a0ae9SChristian Brauner saved_errno = errno; 128575a0ae9SChristian Brauner close(pidfd); 129575a0ae9SChristian Brauner if (ret == 0) 130575a0ae9SChristian Brauner ksft_exit_fail_msg( 131575a0ae9SChristian Brauner "%s test: Managed to send signal to process even though it should have failed\n", 132575a0ae9SChristian Brauner test_name); 133575a0ae9SChristian Brauner 134575a0ae9SChristian Brauner if (saved_errno != ESRCH) 135575a0ae9SChristian Brauner ksft_exit_fail_msg( 136575a0ae9SChristian Brauner "%s test: Expected to receive ESRCH as errno value but received %d instead\n", 137575a0ae9SChristian Brauner test_name, saved_errno); 138575a0ae9SChristian Brauner 139575a0ae9SChristian Brauner ksft_test_result_pass("%s test: Failed to send signal as expected\n", 140575a0ae9SChristian Brauner test_name); 141575a0ae9SChristian Brauner return 0; 142575a0ae9SChristian Brauner } 143575a0ae9SChristian Brauner 144575a0ae9SChristian Brauner /* 145575a0ae9SChristian Brauner * Maximum number of cycles we allow. This is equivalent to PID_MAX_DEFAULT. 146575a0ae9SChristian Brauner * If users set a higher limit or we have cycled PIDFD_MAX_DEFAULT number of 147575a0ae9SChristian Brauner * times then we skip the test to not go into an infinite loop or block for a 148575a0ae9SChristian Brauner * long time. 149575a0ae9SChristian Brauner */ 150575a0ae9SChristian Brauner #define PIDFD_MAX_DEFAULT 0x8000 151575a0ae9SChristian Brauner 152575a0ae9SChristian Brauner static int test_pidfd_send_signal_recycled_pid_fail(void) 153575a0ae9SChristian Brauner { 154575a0ae9SChristian Brauner int i, ret; 155575a0ae9SChristian Brauner pid_t pid1; 156575a0ae9SChristian Brauner const char *test_name = "pidfd_send_signal signal recycled pid"; 157575a0ae9SChristian Brauner 158bb91c0caSPaolo Bonzini if (!have_pidfd_send_signal) { 159bb91c0caSPaolo Bonzini ksft_test_result_skip( 160bb91c0caSPaolo Bonzini "%s test: pidfd_send_signal() syscall not supported\n", 161bb91c0caSPaolo Bonzini test_name); 162bb91c0caSPaolo Bonzini return 0; 163bb91c0caSPaolo Bonzini } 164bb91c0caSPaolo Bonzini 165575a0ae9SChristian Brauner ret = unshare(CLONE_NEWPID); 16605790fd7SPaolo Bonzini if (ret < 0) { 16705790fd7SPaolo Bonzini if (errno == EPERM) { 16805790fd7SPaolo Bonzini ksft_test_result_skip("%s test: Unsharing pid namespace not permitted\n", 16905790fd7SPaolo Bonzini test_name); 17005790fd7SPaolo Bonzini return 0; 17105790fd7SPaolo Bonzini } 172575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to unshare pid namespace\n", 173575a0ae9SChristian Brauner test_name); 17405790fd7SPaolo Bonzini } 175575a0ae9SChristian Brauner 176575a0ae9SChristian Brauner ret = unshare(CLONE_NEWNS); 17705790fd7SPaolo Bonzini if (ret < 0) { 17805790fd7SPaolo Bonzini if (errno == EPERM) { 17905790fd7SPaolo Bonzini ksft_test_result_skip("%s test: Unsharing mount namespace not permitted\n", 180575a0ae9SChristian Brauner test_name); 18105790fd7SPaolo Bonzini return 0; 18205790fd7SPaolo Bonzini } 18305790fd7SPaolo Bonzini ksft_exit_fail_msg("%s test: Failed to unshare mount namespace\n", 18405790fd7SPaolo Bonzini test_name); 18505790fd7SPaolo Bonzini } 186575a0ae9SChristian Brauner 187575a0ae9SChristian Brauner ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0); 188575a0ae9SChristian Brauner if (ret < 0) 189575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to remount / private\n", 190575a0ae9SChristian Brauner test_name); 191575a0ae9SChristian Brauner 192575a0ae9SChristian Brauner /* pid 1 in new pid namespace */ 193575a0ae9SChristian Brauner pid1 = fork(); 194575a0ae9SChristian Brauner if (pid1 < 0) 195575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to create new process\n", 196575a0ae9SChristian Brauner test_name); 197575a0ae9SChristian Brauner 198575a0ae9SChristian Brauner if (pid1 == 0) { 199575a0ae9SChristian Brauner char buf[256]; 200575a0ae9SChristian Brauner pid_t pid2; 201575a0ae9SChristian Brauner int pidfd = -1; 202575a0ae9SChristian Brauner 203575a0ae9SChristian Brauner (void)umount2("/proc", MNT_DETACH); 204575a0ae9SChristian Brauner ret = mount("proc", "/proc", "proc", 0, NULL); 205575a0ae9SChristian Brauner if (ret < 0) 206575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 207575a0ae9SChristian Brauner 208575a0ae9SChristian Brauner /* grab pid PID_RECYCLE */ 209575a0ae9SChristian Brauner for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) { 210575a0ae9SChristian Brauner pid2 = fork(); 211575a0ae9SChristian Brauner if (pid2 < 0) 212575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 213575a0ae9SChristian Brauner 214575a0ae9SChristian Brauner if (pid2 == 0) 215575a0ae9SChristian Brauner _exit(PIDFD_PASS); 216575a0ae9SChristian Brauner 217575a0ae9SChristian Brauner if (pid2 == PID_RECYCLE) { 218575a0ae9SChristian Brauner snprintf(buf, sizeof(buf), "/proc/%d", pid2); 219575a0ae9SChristian Brauner ksft_print_msg("pid to recycle is %d\n", pid2); 220575a0ae9SChristian Brauner pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); 221575a0ae9SChristian Brauner } 222575a0ae9SChristian Brauner 223575a0ae9SChristian Brauner if (wait_for_pid(pid2)) 224575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 225575a0ae9SChristian Brauner 226575a0ae9SChristian Brauner if (pid2 >= PID_RECYCLE) 227575a0ae9SChristian Brauner break; 228575a0ae9SChristian Brauner } 229575a0ae9SChristian Brauner 230575a0ae9SChristian Brauner /* 231575a0ae9SChristian Brauner * We want to be as predictable as we can so if we haven't been 232575a0ae9SChristian Brauner * able to grab pid PID_RECYCLE skip the test. 233575a0ae9SChristian Brauner */ 234575a0ae9SChristian Brauner if (pid2 != PID_RECYCLE) { 235575a0ae9SChristian Brauner /* skip test */ 236575a0ae9SChristian Brauner close(pidfd); 237575a0ae9SChristian Brauner _exit(PIDFD_SKIP); 238575a0ae9SChristian Brauner } 239575a0ae9SChristian Brauner 240575a0ae9SChristian Brauner if (pidfd < 0) 241575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 242575a0ae9SChristian Brauner 243575a0ae9SChristian Brauner for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) { 244575a0ae9SChristian Brauner char c; 245575a0ae9SChristian Brauner int pipe_fds[2]; 246575a0ae9SChristian Brauner pid_t recycled_pid; 247575a0ae9SChristian Brauner int child_ret = PIDFD_PASS; 248575a0ae9SChristian Brauner 249575a0ae9SChristian Brauner ret = pipe2(pipe_fds, O_CLOEXEC); 250575a0ae9SChristian Brauner if (ret < 0) 251575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 252575a0ae9SChristian Brauner 253575a0ae9SChristian Brauner recycled_pid = fork(); 254575a0ae9SChristian Brauner if (recycled_pid < 0) 255575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 256575a0ae9SChristian Brauner 257575a0ae9SChristian Brauner if (recycled_pid == 0) { 258575a0ae9SChristian Brauner close(pipe_fds[1]); 259575a0ae9SChristian Brauner (void)read(pipe_fds[0], &c, 1); 260575a0ae9SChristian Brauner close(pipe_fds[0]); 261575a0ae9SChristian Brauner 262575a0ae9SChristian Brauner _exit(PIDFD_PASS); 263575a0ae9SChristian Brauner } 264575a0ae9SChristian Brauner 265575a0ae9SChristian Brauner /* 266575a0ae9SChristian Brauner * Stop the child so we can inspect whether we have 267575a0ae9SChristian Brauner * recycled pid PID_RECYCLE. 268575a0ae9SChristian Brauner */ 269575a0ae9SChristian Brauner close(pipe_fds[0]); 270575a0ae9SChristian Brauner ret = kill(recycled_pid, SIGSTOP); 271575a0ae9SChristian Brauner close(pipe_fds[1]); 272575a0ae9SChristian Brauner if (ret) { 273575a0ae9SChristian Brauner (void)wait_for_pid(recycled_pid); 274575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 275575a0ae9SChristian Brauner } 276575a0ae9SChristian Brauner 277575a0ae9SChristian Brauner /* 278575a0ae9SChristian Brauner * We have recycled the pid. Try to signal it. This 279575a0ae9SChristian Brauner * needs to fail since this is a different process than 280575a0ae9SChristian Brauner * the one the pidfd refers to. 281575a0ae9SChristian Brauner */ 282575a0ae9SChristian Brauner if (recycled_pid == PID_RECYCLE) { 283575a0ae9SChristian Brauner ret = sys_pidfd_send_signal(pidfd, SIGCONT, 284575a0ae9SChristian Brauner NULL, 0); 285575a0ae9SChristian Brauner if (ret && errno == ESRCH) 286575a0ae9SChristian Brauner child_ret = PIDFD_XFAIL; 287575a0ae9SChristian Brauner else 288575a0ae9SChristian Brauner child_ret = PIDFD_FAIL; 289575a0ae9SChristian Brauner } 290575a0ae9SChristian Brauner 291575a0ae9SChristian Brauner /* let the process move on */ 292575a0ae9SChristian Brauner ret = kill(recycled_pid, SIGCONT); 293575a0ae9SChristian Brauner if (ret) 294575a0ae9SChristian Brauner (void)kill(recycled_pid, SIGKILL); 295575a0ae9SChristian Brauner 296575a0ae9SChristian Brauner if (wait_for_pid(recycled_pid)) 297575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 298575a0ae9SChristian Brauner 299575a0ae9SChristian Brauner switch (child_ret) { 300575a0ae9SChristian Brauner case PIDFD_FAIL: 301575a0ae9SChristian Brauner /* fallthrough */ 302575a0ae9SChristian Brauner case PIDFD_XFAIL: 303575a0ae9SChristian Brauner _exit(child_ret); 304575a0ae9SChristian Brauner case PIDFD_PASS: 305575a0ae9SChristian Brauner break; 306575a0ae9SChristian Brauner default: 307575a0ae9SChristian Brauner /* not reached */ 308575a0ae9SChristian Brauner _exit(PIDFD_ERROR); 309575a0ae9SChristian Brauner } 310575a0ae9SChristian Brauner 311575a0ae9SChristian Brauner /* 312575a0ae9SChristian Brauner * If the user set a custom pid_max limit we could be 313575a0ae9SChristian Brauner * in the millions. 314575a0ae9SChristian Brauner * Skip the test in this case. 315575a0ae9SChristian Brauner */ 316575a0ae9SChristian Brauner if (recycled_pid > PIDFD_MAX_DEFAULT) 317575a0ae9SChristian Brauner _exit(PIDFD_SKIP); 318575a0ae9SChristian Brauner } 319575a0ae9SChristian Brauner 320575a0ae9SChristian Brauner /* failed to recycle pid */ 321575a0ae9SChristian Brauner _exit(PIDFD_SKIP); 322575a0ae9SChristian Brauner } 323575a0ae9SChristian Brauner 324575a0ae9SChristian Brauner ret = wait_for_pid(pid1); 325575a0ae9SChristian Brauner switch (ret) { 326575a0ae9SChristian Brauner case PIDFD_FAIL: 327575a0ae9SChristian Brauner ksft_exit_fail_msg( 328575a0ae9SChristian Brauner "%s test: Managed to signal recycled pid %d\n", 329575a0ae9SChristian Brauner test_name, PID_RECYCLE); 330575a0ae9SChristian Brauner case PIDFD_PASS: 331575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to recycle pid %d\n", 332575a0ae9SChristian Brauner test_name, PID_RECYCLE); 333575a0ae9SChristian Brauner case PIDFD_SKIP: 3340b18fed9STommi Rantala ksft_test_result_skip("%s test: Skipping test\n", test_name); 335575a0ae9SChristian Brauner ret = 0; 336575a0ae9SChristian Brauner break; 337575a0ae9SChristian Brauner case PIDFD_XFAIL: 338575a0ae9SChristian Brauner ksft_test_result_pass( 339575a0ae9SChristian Brauner "%s test: Failed to signal recycled pid as expected\n", 340575a0ae9SChristian Brauner test_name); 341575a0ae9SChristian Brauner ret = 0; 342575a0ae9SChristian Brauner break; 343575a0ae9SChristian Brauner default /* PIDFD_ERROR */: 344575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Error while running tests\n", 345575a0ae9SChristian Brauner test_name); 346575a0ae9SChristian Brauner } 347575a0ae9SChristian Brauner 348575a0ae9SChristian Brauner return ret; 349575a0ae9SChristian Brauner } 350575a0ae9SChristian Brauner 351575a0ae9SChristian Brauner static int test_pidfd_send_signal_syscall_support(void) 352575a0ae9SChristian Brauner { 353575a0ae9SChristian Brauner int pidfd, ret; 354575a0ae9SChristian Brauner const char *test_name = "pidfd_send_signal check for support"; 355575a0ae9SChristian Brauner 356575a0ae9SChristian Brauner pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC); 357575a0ae9SChristian Brauner if (pidfd < 0) 358575a0ae9SChristian Brauner ksft_exit_fail_msg( 359575a0ae9SChristian Brauner "%s test: Failed to open process file descriptor\n", 360575a0ae9SChristian Brauner test_name); 361575a0ae9SChristian Brauner 362575a0ae9SChristian Brauner ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); 363575a0ae9SChristian Brauner if (ret < 0) { 364bb91c0caSPaolo Bonzini if (errno == ENOSYS) { 365bb91c0caSPaolo Bonzini ksft_test_result_skip( 3663884ae44SChristian Brauner "%s test: pidfd_send_signal() syscall not supported\n", 367575a0ae9SChristian Brauner test_name); 368bb91c0caSPaolo Bonzini return 0; 369bb91c0caSPaolo Bonzini } 370575a0ae9SChristian Brauner ksft_exit_fail_msg("%s test: Failed to send signal\n", 371575a0ae9SChristian Brauner test_name); 372575a0ae9SChristian Brauner } 373575a0ae9SChristian Brauner 374bb91c0caSPaolo Bonzini have_pidfd_send_signal = true; 375575a0ae9SChristian Brauner close(pidfd); 376575a0ae9SChristian Brauner ksft_test_result_pass( 377575a0ae9SChristian Brauner "%s test: pidfd_send_signal() syscall is supported. Tests can be executed\n", 378575a0ae9SChristian Brauner test_name); 379575a0ae9SChristian Brauner return 0; 380575a0ae9SChristian Brauner } 381575a0ae9SChristian Brauner 382740378dcSJoel Fernandes (Google) static void *test_pidfd_poll_exec_thread(void *priv) 383740378dcSJoel Fernandes (Google) { 384740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n", 385740378dcSJoel Fernandes (Google) getpid(), syscall(SYS_gettid)); 386740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: doing exec of sleep\n"); 387740378dcSJoel Fernandes (Google) 388740378dcSJoel Fernandes (Google) execl("/bin/sleep", "sleep", str(CHILD_THREAD_MIN_WAIT), (char *)NULL); 389740378dcSJoel Fernandes (Google) 390740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", 391740378dcSJoel Fernandes (Google) getpid(), syscall(SYS_gettid)); 392740378dcSJoel Fernandes (Google) return NULL; 393740378dcSJoel Fernandes (Google) } 394740378dcSJoel Fernandes (Google) 395740378dcSJoel Fernandes (Google) static void poll_pidfd(const char *test_name, int pidfd) 396740378dcSJoel Fernandes (Google) { 397740378dcSJoel Fernandes (Google) int c; 398740378dcSJoel Fernandes (Google) int epoll_fd = epoll_create1(EPOLL_CLOEXEC); 399740378dcSJoel Fernandes (Google) struct epoll_event event, events[MAX_EVENTS]; 400740378dcSJoel Fernandes (Google) 401740378dcSJoel Fernandes (Google) if (epoll_fd == -1) 402740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor " 403740378dcSJoel Fernandes (Google) "(errno %d)\n", 404740378dcSJoel Fernandes (Google) test_name, errno); 405740378dcSJoel Fernandes (Google) 406740378dcSJoel Fernandes (Google) event.events = EPOLLIN; 407740378dcSJoel Fernandes (Google) event.data.fd = pidfd; 408740378dcSJoel Fernandes (Google) 409740378dcSJoel Fernandes (Google) if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) { 410740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: Failed to add epoll file descriptor " 411740378dcSJoel Fernandes (Google) "(errno %d)\n", 412740378dcSJoel Fernandes (Google) test_name, errno); 413740378dcSJoel Fernandes (Google) } 414740378dcSJoel Fernandes (Google) 415740378dcSJoel Fernandes (Google) c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000); 416740378dcSJoel Fernandes (Google) if (c != 1 || !(events[0].events & EPOLLIN)) 41789c1017aSZhao Gongyi ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x) " 418740378dcSJoel Fernandes (Google) "(errno %d)\n", 419740378dcSJoel Fernandes (Google) test_name, c, events[0].events, errno); 420740378dcSJoel Fernandes (Google) 421740378dcSJoel Fernandes (Google) close(epoll_fd); 422740378dcSJoel Fernandes (Google) return; 423740378dcSJoel Fernandes (Google) 424740378dcSJoel Fernandes (Google) } 425740378dcSJoel Fernandes (Google) 426740378dcSJoel Fernandes (Google) static int child_poll_exec_test(void *args) 427740378dcSJoel Fernandes (Google) { 428740378dcSJoel Fernandes (Google) pthread_t t1; 429740378dcSJoel Fernandes (Google) 430740378dcSJoel Fernandes (Google) ksft_print_msg("Child (pidfd): starting. pid %d tid %d\n", getpid(), 431740378dcSJoel Fernandes (Google) syscall(SYS_gettid)); 432740378dcSJoel Fernandes (Google) pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL); 433740378dcSJoel Fernandes (Google) /* 434740378dcSJoel Fernandes (Google) * Exec in the non-leader thread will destroy the leader immediately. 435740378dcSJoel Fernandes (Google) * If the wait in the parent returns too soon, the test fails. 436740378dcSJoel Fernandes (Google) */ 437740378dcSJoel Fernandes (Google) while (1) 438740378dcSJoel Fernandes (Google) sleep(1); 4393d982441SLi Zhijian 4403d982441SLi Zhijian return 0; 441740378dcSJoel Fernandes (Google) } 442740378dcSJoel Fernandes (Google) 443740378dcSJoel Fernandes (Google) static void test_pidfd_poll_exec(int use_waitpid) 444740378dcSJoel Fernandes (Google) { 445740378dcSJoel Fernandes (Google) int pid, pidfd = 0; 446740378dcSJoel Fernandes (Google) int status, ret; 447740378dcSJoel Fernandes (Google) time_t prog_start = time(NULL); 448740378dcSJoel Fernandes (Google) const char *test_name = "pidfd_poll check for premature notification on child thread exec"; 449740378dcSJoel Fernandes (Google) 450740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: pid: %d\n", getpid()); 451740378dcSJoel Fernandes (Google) pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test); 452740378dcSJoel Fernandes (Google) if (pid < 0) 453740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n", 454740378dcSJoel Fernandes (Google) test_name, pid, errno); 455740378dcSJoel Fernandes (Google) 456740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); 457740378dcSJoel Fernandes (Google) 458740378dcSJoel Fernandes (Google) if (use_waitpid) { 459740378dcSJoel Fernandes (Google) ret = waitpid(pid, &status, 0); 460740378dcSJoel Fernandes (Google) if (ret == -1) 461740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: error\n"); 462740378dcSJoel Fernandes (Google) 463740378dcSJoel Fernandes (Google) if (ret == pid) 464740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: Child process waited for.\n"); 465740378dcSJoel Fernandes (Google) } else { 466740378dcSJoel Fernandes (Google) poll_pidfd(test_name, pidfd); 467740378dcSJoel Fernandes (Google) } 468740378dcSJoel Fernandes (Google) 469740378dcSJoel Fernandes (Google) time_t prog_time = time(NULL) - prog_start; 470740378dcSJoel Fernandes (Google) 471740378dcSJoel Fernandes (Google) ksft_print_msg("Time waited for child: %lu\n", prog_time); 472740378dcSJoel Fernandes (Google) 473740378dcSJoel Fernandes (Google) close(pidfd); 474740378dcSJoel Fernandes (Google) 475740378dcSJoel Fernandes (Google) if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2) 476740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: Failed\n", test_name); 477740378dcSJoel Fernandes (Google) else 478740378dcSJoel Fernandes (Google) ksft_test_result_pass("%s test: Passed\n", test_name); 479740378dcSJoel Fernandes (Google) } 480740378dcSJoel Fernandes (Google) 481740378dcSJoel Fernandes (Google) static void *test_pidfd_poll_leader_exit_thread(void *priv) 482740378dcSJoel Fernandes (Google) { 483740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n", 484740378dcSJoel Fernandes (Google) getpid(), syscall(SYS_gettid)); 485740378dcSJoel Fernandes (Google) sleep(CHILD_THREAD_MIN_WAIT); 486740378dcSJoel Fernandes (Google) ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", getpid(), syscall(SYS_gettid)); 487740378dcSJoel Fernandes (Google) return NULL; 488740378dcSJoel Fernandes (Google) } 489740378dcSJoel Fernandes (Google) 490740378dcSJoel Fernandes (Google) static time_t *child_exit_secs; 491740378dcSJoel Fernandes (Google) static int child_poll_leader_exit_test(void *args) 492740378dcSJoel Fernandes (Google) { 493740378dcSJoel Fernandes (Google) pthread_t t1, t2; 494740378dcSJoel Fernandes (Google) 495740378dcSJoel Fernandes (Google) ksft_print_msg("Child: starting. pid %d tid %d\n", getpid(), syscall(SYS_gettid)); 496740378dcSJoel Fernandes (Google) pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL); 497740378dcSJoel Fernandes (Google) pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL); 498740378dcSJoel Fernandes (Google) 499740378dcSJoel Fernandes (Google) /* 500740378dcSJoel Fernandes (Google) * glibc exit calls exit_group syscall, so explicity call exit only 501740378dcSJoel Fernandes (Google) * so that only the group leader exits, leaving the threads alone. 502740378dcSJoel Fernandes (Google) */ 503740378dcSJoel Fernandes (Google) *child_exit_secs = time(NULL); 504740378dcSJoel Fernandes (Google) syscall(SYS_exit, 0); 505e2aa5e65SAxel Rasmussen /* Never reached, but appeases compiler thinking we should return. */ 506e2aa5e65SAxel Rasmussen exit(0); 507740378dcSJoel Fernandes (Google) } 508740378dcSJoel Fernandes (Google) 509740378dcSJoel Fernandes (Google) static void test_pidfd_poll_leader_exit(int use_waitpid) 510740378dcSJoel Fernandes (Google) { 511740378dcSJoel Fernandes (Google) int pid, pidfd = 0; 512e2aa5e65SAxel Rasmussen int status, ret = 0; 513740378dcSJoel Fernandes (Google) const char *test_name = "pidfd_poll check for premature notification on non-empty" 514740378dcSJoel Fernandes (Google) "group leader exit"; 515740378dcSJoel Fernandes (Google) 516740378dcSJoel Fernandes (Google) child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE, 517740378dcSJoel Fernandes (Google) MAP_SHARED | MAP_ANONYMOUS, -1, 0); 518740378dcSJoel Fernandes (Google) 519740378dcSJoel Fernandes (Google) if (child_exit_secs == MAP_FAILED) 520740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: mmap failed (errno %d)\n", 521740378dcSJoel Fernandes (Google) test_name, errno); 522740378dcSJoel Fernandes (Google) 523740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: pid: %d\n", getpid()); 524740378dcSJoel Fernandes (Google) pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test); 525740378dcSJoel Fernandes (Google) if (pid < 0) 526740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n", 527740378dcSJoel Fernandes (Google) test_name, pid, errno); 528740378dcSJoel Fernandes (Google) 529740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); 530740378dcSJoel Fernandes (Google) 531740378dcSJoel Fernandes (Google) if (use_waitpid) { 532740378dcSJoel Fernandes (Google) ret = waitpid(pid, &status, 0); 533740378dcSJoel Fernandes (Google) if (ret == -1) 534740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: error\n"); 535740378dcSJoel Fernandes (Google) } else { 536740378dcSJoel Fernandes (Google) /* 537740378dcSJoel Fernandes (Google) * This sleep tests for the case where if the child exits, and is in 538740378dcSJoel Fernandes (Google) * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll 539740378dcSJoel Fernandes (Google) * doesn't prematurely return even though there are active threads 540740378dcSJoel Fernandes (Google) */ 541740378dcSJoel Fernandes (Google) sleep(1); 542740378dcSJoel Fernandes (Google) poll_pidfd(test_name, pidfd); 543740378dcSJoel Fernandes (Google) } 544740378dcSJoel Fernandes (Google) 545740378dcSJoel Fernandes (Google) if (ret == pid) 546740378dcSJoel Fernandes (Google) ksft_print_msg("Parent: Child process waited for.\n"); 547740378dcSJoel Fernandes (Google) 548740378dcSJoel Fernandes (Google) time_t since_child_exit = time(NULL) - *child_exit_secs; 549740378dcSJoel Fernandes (Google) 550740378dcSJoel Fernandes (Google) ksft_print_msg("Time since child exit: %lu\n", since_child_exit); 551740378dcSJoel Fernandes (Google) 552740378dcSJoel Fernandes (Google) close(pidfd); 553740378dcSJoel Fernandes (Google) 554740378dcSJoel Fernandes (Google) if (since_child_exit < CHILD_THREAD_MIN_WAIT || 555740378dcSJoel Fernandes (Google) since_child_exit > CHILD_THREAD_MIN_WAIT + 2) 556740378dcSJoel Fernandes (Google) ksft_exit_fail_msg("%s test: Failed\n", test_name); 557740378dcSJoel Fernandes (Google) else 558740378dcSJoel Fernandes (Google) ksft_test_result_pass("%s test: Passed\n", test_name); 559740378dcSJoel Fernandes (Google) } 560740378dcSJoel Fernandes (Google) 561575a0ae9SChristian Brauner int main(int argc, char **argv) 562575a0ae9SChristian Brauner { 563575a0ae9SChristian Brauner ksft_print_header(); 564bb91c0caSPaolo Bonzini ksft_set_plan(8); 565575a0ae9SChristian Brauner 566740378dcSJoel Fernandes (Google) test_pidfd_poll_exec(0); 567740378dcSJoel Fernandes (Google) test_pidfd_poll_exec(1); 568740378dcSJoel Fernandes (Google) test_pidfd_poll_leader_exit(0); 569740378dcSJoel Fernandes (Google) test_pidfd_poll_leader_exit(1); 570575a0ae9SChristian Brauner test_pidfd_send_signal_syscall_support(); 571575a0ae9SChristian Brauner test_pidfd_send_signal_simple_success(); 572575a0ae9SChristian Brauner test_pidfd_send_signal_exited_fail(); 573575a0ae9SChristian Brauner test_pidfd_send_signal_recycled_pid_fail(); 574575a0ae9SChristian Brauner 575575a0ae9SChristian Brauner return ksft_exit_pass(); 576575a0ae9SChristian Brauner } 577