162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#define _GNU_SOURCE 462306a36Sopenharmony_ci#include <errno.h> 562306a36Sopenharmony_ci#include <fcntl.h> 662306a36Sopenharmony_ci#include <linux/types.h> 762306a36Sopenharmony_ci#include <pthread.h> 862306a36Sopenharmony_ci#include <sched.h> 962306a36Sopenharmony_ci#include <signal.h> 1062306a36Sopenharmony_ci#include <stdio.h> 1162306a36Sopenharmony_ci#include <stdbool.h> 1262306a36Sopenharmony_ci#include <stdlib.h> 1362306a36Sopenharmony_ci#include <string.h> 1462306a36Sopenharmony_ci#include <syscall.h> 1562306a36Sopenharmony_ci#include <sys/epoll.h> 1662306a36Sopenharmony_ci#include <sys/mman.h> 1762306a36Sopenharmony_ci#include <sys/mount.h> 1862306a36Sopenharmony_ci#include <sys/wait.h> 1962306a36Sopenharmony_ci#include <time.h> 2062306a36Sopenharmony_ci#include <unistd.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "pidfd.h" 2362306a36Sopenharmony_ci#include "../kselftest.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define str(s) _str(s) 2662306a36Sopenharmony_ci#define _str(s) #s 2762306a36Sopenharmony_ci#define CHILD_THREAD_MIN_WAIT 3 /* seconds */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define MAX_EVENTS 5 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic bool have_pidfd_send_signal; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *)) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci size_t stack_size = 1024; 3662306a36Sopenharmony_ci char *stack[1024] = { 0 }; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#ifdef __ia64__ 3962306a36Sopenharmony_ci return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd); 4062306a36Sopenharmony_ci#else 4162306a36Sopenharmony_ci return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd); 4262306a36Sopenharmony_ci#endif 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic int signal_received; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic void set_signal_received_on_sigusr1(int sig) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci if (sig == SIGUSR1) 5062306a36Sopenharmony_ci signal_received = 1; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * Straightforward test to see whether pidfd_send_signal() works is to send 5562306a36Sopenharmony_ci * a signal to ourself. 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_cistatic int test_pidfd_send_signal_simple_success(void) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci int pidfd, ret; 6062306a36Sopenharmony_ci const char *test_name = "pidfd_send_signal send SIGUSR1"; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (!have_pidfd_send_signal) { 6362306a36Sopenharmony_ci ksft_test_result_skip( 6462306a36Sopenharmony_ci "%s test: pidfd_send_signal() syscall not supported\n", 6562306a36Sopenharmony_ci test_name); 6662306a36Sopenharmony_ci return 0; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC); 7062306a36Sopenharmony_ci if (pidfd < 0) 7162306a36Sopenharmony_ci ksft_exit_fail_msg( 7262306a36Sopenharmony_ci "%s test: Failed to open process file descriptor\n", 7362306a36Sopenharmony_ci test_name); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci signal(SIGUSR1, set_signal_received_on_sigusr1); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci ret = sys_pidfd_send_signal(pidfd, SIGUSR1, NULL, 0); 7862306a36Sopenharmony_ci close(pidfd); 7962306a36Sopenharmony_ci if (ret < 0) 8062306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to send signal\n", 8162306a36Sopenharmony_ci test_name); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (signal_received != 1) 8462306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to receive signal\n", 8562306a36Sopenharmony_ci test_name); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci signal_received = 0; 8862306a36Sopenharmony_ci ksft_test_result_pass("%s test: Sent signal\n", test_name); 8962306a36Sopenharmony_ci return 0; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic int test_pidfd_send_signal_exited_fail(void) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci int pidfd, ret, saved_errno; 9562306a36Sopenharmony_ci char buf[256]; 9662306a36Sopenharmony_ci pid_t pid; 9762306a36Sopenharmony_ci const char *test_name = "pidfd_send_signal signal exited process"; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (!have_pidfd_send_signal) { 10062306a36Sopenharmony_ci ksft_test_result_skip( 10162306a36Sopenharmony_ci "%s test: pidfd_send_signal() syscall not supported\n", 10262306a36Sopenharmony_ci test_name); 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci pid = fork(); 10762306a36Sopenharmony_ci if (pid < 0) 10862306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to create new process\n", 10962306a36Sopenharmony_ci test_name); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (pid == 0) 11262306a36Sopenharmony_ci _exit(EXIT_SUCCESS); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "/proc/%d", pid); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci ret = wait_for_pid(pid); 11962306a36Sopenharmony_ci ksft_print_msg("waitpid WEXITSTATUS=%d\n", ret); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (pidfd < 0) 12262306a36Sopenharmony_ci ksft_exit_fail_msg( 12362306a36Sopenharmony_ci "%s test: Failed to open process file descriptor\n", 12462306a36Sopenharmony_ci test_name); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); 12762306a36Sopenharmony_ci saved_errno = errno; 12862306a36Sopenharmony_ci close(pidfd); 12962306a36Sopenharmony_ci if (ret == 0) 13062306a36Sopenharmony_ci ksft_exit_fail_msg( 13162306a36Sopenharmony_ci "%s test: Managed to send signal to process even though it should have failed\n", 13262306a36Sopenharmony_ci test_name); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (saved_errno != ESRCH) 13562306a36Sopenharmony_ci ksft_exit_fail_msg( 13662306a36Sopenharmony_ci "%s test: Expected to receive ESRCH as errno value but received %d instead\n", 13762306a36Sopenharmony_ci test_name, saved_errno); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci ksft_test_result_pass("%s test: Failed to send signal as expected\n", 14062306a36Sopenharmony_ci test_name); 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* 14562306a36Sopenharmony_ci * Maximum number of cycles we allow. This is equivalent to PID_MAX_DEFAULT. 14662306a36Sopenharmony_ci * If users set a higher limit or we have cycled PIDFD_MAX_DEFAULT number of 14762306a36Sopenharmony_ci * times then we skip the test to not go into an infinite loop or block for a 14862306a36Sopenharmony_ci * long time. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci#define PIDFD_MAX_DEFAULT 0x8000 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic int test_pidfd_send_signal_recycled_pid_fail(void) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci int i, ret; 15562306a36Sopenharmony_ci pid_t pid1; 15662306a36Sopenharmony_ci const char *test_name = "pidfd_send_signal signal recycled pid"; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (!have_pidfd_send_signal) { 15962306a36Sopenharmony_ci ksft_test_result_skip( 16062306a36Sopenharmony_ci "%s test: pidfd_send_signal() syscall not supported\n", 16162306a36Sopenharmony_ci test_name); 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci ret = unshare(CLONE_NEWPID); 16662306a36Sopenharmony_ci if (ret < 0) { 16762306a36Sopenharmony_ci if (errno == EPERM) { 16862306a36Sopenharmony_ci ksft_test_result_skip("%s test: Unsharing pid namespace not permitted\n", 16962306a36Sopenharmony_ci test_name); 17062306a36Sopenharmony_ci return 0; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to unshare pid namespace\n", 17362306a36Sopenharmony_ci test_name); 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci ret = unshare(CLONE_NEWNS); 17762306a36Sopenharmony_ci if (ret < 0) { 17862306a36Sopenharmony_ci if (errno == EPERM) { 17962306a36Sopenharmony_ci ksft_test_result_skip("%s test: Unsharing mount namespace not permitted\n", 18062306a36Sopenharmony_ci test_name); 18162306a36Sopenharmony_ci return 0; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to unshare mount namespace\n", 18462306a36Sopenharmony_ci test_name); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0); 18862306a36Sopenharmony_ci if (ret < 0) 18962306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to remount / private\n", 19062306a36Sopenharmony_ci test_name); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* pid 1 in new pid namespace */ 19362306a36Sopenharmony_ci pid1 = fork(); 19462306a36Sopenharmony_ci if (pid1 < 0) 19562306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to create new process\n", 19662306a36Sopenharmony_ci test_name); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (pid1 == 0) { 19962306a36Sopenharmony_ci char buf[256]; 20062306a36Sopenharmony_ci pid_t pid2; 20162306a36Sopenharmony_ci int pidfd = -1; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci (void)umount2("/proc", MNT_DETACH); 20462306a36Sopenharmony_ci ret = mount("proc", "/proc", "proc", 0, NULL); 20562306a36Sopenharmony_ci if (ret < 0) 20662306a36Sopenharmony_ci _exit(PIDFD_ERROR); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* grab pid PID_RECYCLE */ 20962306a36Sopenharmony_ci for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) { 21062306a36Sopenharmony_ci pid2 = fork(); 21162306a36Sopenharmony_ci if (pid2 < 0) 21262306a36Sopenharmony_ci _exit(PIDFD_ERROR); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (pid2 == 0) 21562306a36Sopenharmony_ci _exit(PIDFD_PASS); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (pid2 == PID_RECYCLE) { 21862306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "/proc/%d", pid2); 21962306a36Sopenharmony_ci ksft_print_msg("pid to recycle is %d\n", pid2); 22062306a36Sopenharmony_ci pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (wait_for_pid(pid2)) 22462306a36Sopenharmony_ci _exit(PIDFD_ERROR); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (pid2 >= PID_RECYCLE) 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* 23162306a36Sopenharmony_ci * We want to be as predictable as we can so if we haven't been 23262306a36Sopenharmony_ci * able to grab pid PID_RECYCLE skip the test. 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_ci if (pid2 != PID_RECYCLE) { 23562306a36Sopenharmony_ci /* skip test */ 23662306a36Sopenharmony_ci close(pidfd); 23762306a36Sopenharmony_ci _exit(PIDFD_SKIP); 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (pidfd < 0) 24162306a36Sopenharmony_ci _exit(PIDFD_ERROR); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) { 24462306a36Sopenharmony_ci char c; 24562306a36Sopenharmony_ci int pipe_fds[2]; 24662306a36Sopenharmony_ci pid_t recycled_pid; 24762306a36Sopenharmony_ci int child_ret = PIDFD_PASS; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci ret = pipe2(pipe_fds, O_CLOEXEC); 25062306a36Sopenharmony_ci if (ret < 0) 25162306a36Sopenharmony_ci _exit(PIDFD_ERROR); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci recycled_pid = fork(); 25462306a36Sopenharmony_ci if (recycled_pid < 0) 25562306a36Sopenharmony_ci _exit(PIDFD_ERROR); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (recycled_pid == 0) { 25862306a36Sopenharmony_ci close(pipe_fds[1]); 25962306a36Sopenharmony_ci (void)read(pipe_fds[0], &c, 1); 26062306a36Sopenharmony_ci close(pipe_fds[0]); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci _exit(PIDFD_PASS); 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* 26662306a36Sopenharmony_ci * Stop the child so we can inspect whether we have 26762306a36Sopenharmony_ci * recycled pid PID_RECYCLE. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci close(pipe_fds[0]); 27062306a36Sopenharmony_ci ret = kill(recycled_pid, SIGSTOP); 27162306a36Sopenharmony_ci close(pipe_fds[1]); 27262306a36Sopenharmony_ci if (ret) { 27362306a36Sopenharmony_ci (void)wait_for_pid(recycled_pid); 27462306a36Sopenharmony_ci _exit(PIDFD_ERROR); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* 27862306a36Sopenharmony_ci * We have recycled the pid. Try to signal it. This 27962306a36Sopenharmony_ci * needs to fail since this is a different process than 28062306a36Sopenharmony_ci * the one the pidfd refers to. 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_ci if (recycled_pid == PID_RECYCLE) { 28362306a36Sopenharmony_ci ret = sys_pidfd_send_signal(pidfd, SIGCONT, 28462306a36Sopenharmony_ci NULL, 0); 28562306a36Sopenharmony_ci if (ret && errno == ESRCH) 28662306a36Sopenharmony_ci child_ret = PIDFD_XFAIL; 28762306a36Sopenharmony_ci else 28862306a36Sopenharmony_ci child_ret = PIDFD_FAIL; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* let the process move on */ 29262306a36Sopenharmony_ci ret = kill(recycled_pid, SIGCONT); 29362306a36Sopenharmony_ci if (ret) 29462306a36Sopenharmony_ci (void)kill(recycled_pid, SIGKILL); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (wait_for_pid(recycled_pid)) 29762306a36Sopenharmony_ci _exit(PIDFD_ERROR); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci switch (child_ret) { 30062306a36Sopenharmony_ci case PIDFD_FAIL: 30162306a36Sopenharmony_ci /* fallthrough */ 30262306a36Sopenharmony_ci case PIDFD_XFAIL: 30362306a36Sopenharmony_ci _exit(child_ret); 30462306a36Sopenharmony_ci case PIDFD_PASS: 30562306a36Sopenharmony_ci break; 30662306a36Sopenharmony_ci default: 30762306a36Sopenharmony_ci /* not reached */ 30862306a36Sopenharmony_ci _exit(PIDFD_ERROR); 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* 31262306a36Sopenharmony_ci * If the user set a custom pid_max limit we could be 31362306a36Sopenharmony_ci * in the millions. 31462306a36Sopenharmony_ci * Skip the test in this case. 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_ci if (recycled_pid > PIDFD_MAX_DEFAULT) 31762306a36Sopenharmony_ci _exit(PIDFD_SKIP); 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* failed to recycle pid */ 32162306a36Sopenharmony_ci _exit(PIDFD_SKIP); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci ret = wait_for_pid(pid1); 32562306a36Sopenharmony_ci switch (ret) { 32662306a36Sopenharmony_ci case PIDFD_FAIL: 32762306a36Sopenharmony_ci ksft_exit_fail_msg( 32862306a36Sopenharmony_ci "%s test: Managed to signal recycled pid %d\n", 32962306a36Sopenharmony_ci test_name, PID_RECYCLE); 33062306a36Sopenharmony_ci case PIDFD_PASS: 33162306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to recycle pid %d\n", 33262306a36Sopenharmony_ci test_name, PID_RECYCLE); 33362306a36Sopenharmony_ci case PIDFD_SKIP: 33462306a36Sopenharmony_ci ksft_test_result_skip("%s test: Skipping test\n", test_name); 33562306a36Sopenharmony_ci ret = 0; 33662306a36Sopenharmony_ci break; 33762306a36Sopenharmony_ci case PIDFD_XFAIL: 33862306a36Sopenharmony_ci ksft_test_result_pass( 33962306a36Sopenharmony_ci "%s test: Failed to signal recycled pid as expected\n", 34062306a36Sopenharmony_ci test_name); 34162306a36Sopenharmony_ci ret = 0; 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci default /* PIDFD_ERROR */: 34462306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Error while running tests\n", 34562306a36Sopenharmony_ci test_name); 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return ret; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic int test_pidfd_send_signal_syscall_support(void) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci int pidfd, ret; 35462306a36Sopenharmony_ci const char *test_name = "pidfd_send_signal check for support"; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC); 35762306a36Sopenharmony_ci if (pidfd < 0) 35862306a36Sopenharmony_ci ksft_exit_fail_msg( 35962306a36Sopenharmony_ci "%s test: Failed to open process file descriptor\n", 36062306a36Sopenharmony_ci test_name); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); 36362306a36Sopenharmony_ci if (ret < 0) { 36462306a36Sopenharmony_ci if (errno == ENOSYS) { 36562306a36Sopenharmony_ci ksft_test_result_skip( 36662306a36Sopenharmony_ci "%s test: pidfd_send_signal() syscall not supported\n", 36762306a36Sopenharmony_ci test_name); 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to send signal\n", 37162306a36Sopenharmony_ci test_name); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci have_pidfd_send_signal = true; 37562306a36Sopenharmony_ci close(pidfd); 37662306a36Sopenharmony_ci ksft_test_result_pass( 37762306a36Sopenharmony_ci "%s test: pidfd_send_signal() syscall is supported. Tests can be executed\n", 37862306a36Sopenharmony_ci test_name); 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic void *test_pidfd_poll_exec_thread(void *priv) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci ksft_print_msg("Child Thread: starting. pid %d tid %ld ; and sleeping\n", 38562306a36Sopenharmony_ci getpid(), syscall(SYS_gettid)); 38662306a36Sopenharmony_ci ksft_print_msg("Child Thread: doing exec of sleep\n"); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci execl("/bin/sleep", "sleep", str(CHILD_THREAD_MIN_WAIT), (char *)NULL); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci ksft_print_msg("Child Thread: DONE. pid %d tid %ld\n", 39162306a36Sopenharmony_ci getpid(), syscall(SYS_gettid)); 39262306a36Sopenharmony_ci return NULL; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic void poll_pidfd(const char *test_name, int pidfd) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci int c; 39862306a36Sopenharmony_ci int epoll_fd = epoll_create1(EPOLL_CLOEXEC); 39962306a36Sopenharmony_ci struct epoll_event event, events[MAX_EVENTS]; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (epoll_fd == -1) 40262306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor " 40362306a36Sopenharmony_ci "(errno %d)\n", 40462306a36Sopenharmony_ci test_name, errno); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci event.events = EPOLLIN; 40762306a36Sopenharmony_ci event.data.fd = pidfd; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) { 41062306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to add epoll file descriptor " 41162306a36Sopenharmony_ci "(errno %d)\n", 41262306a36Sopenharmony_ci test_name, errno); 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000); 41662306a36Sopenharmony_ci if (c != 1 || !(events[0].events & EPOLLIN)) 41762306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x) " 41862306a36Sopenharmony_ci "(errno %d)\n", 41962306a36Sopenharmony_ci test_name, c, events[0].events, errno); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci close(epoll_fd); 42262306a36Sopenharmony_ci return; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic int child_poll_exec_test(void *args) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci pthread_t t1; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci ksft_print_msg("Child (pidfd): starting. pid %d tid %ld\n", getpid(), 43162306a36Sopenharmony_ci syscall(SYS_gettid)); 43262306a36Sopenharmony_ci pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL); 43362306a36Sopenharmony_ci /* 43462306a36Sopenharmony_ci * Exec in the non-leader thread will destroy the leader immediately. 43562306a36Sopenharmony_ci * If the wait in the parent returns too soon, the test fails. 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_ci while (1) 43862306a36Sopenharmony_ci sleep(1); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci return 0; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic void test_pidfd_poll_exec(int use_waitpid) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci int pid, pidfd = 0; 44662306a36Sopenharmony_ci int status, ret; 44762306a36Sopenharmony_ci time_t prog_start = time(NULL); 44862306a36Sopenharmony_ci const char *test_name = "pidfd_poll check for premature notification on child thread exec"; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci ksft_print_msg("Parent: pid: %d\n", getpid()); 45162306a36Sopenharmony_ci pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test); 45262306a36Sopenharmony_ci if (pid < 0) 45362306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n", 45462306a36Sopenharmony_ci test_name, pid, errno); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (use_waitpid) { 45962306a36Sopenharmony_ci ret = waitpid(pid, &status, 0); 46062306a36Sopenharmony_ci if (ret == -1) 46162306a36Sopenharmony_ci ksft_print_msg("Parent: error\n"); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (ret == pid) 46462306a36Sopenharmony_ci ksft_print_msg("Parent: Child process waited for.\n"); 46562306a36Sopenharmony_ci } else { 46662306a36Sopenharmony_ci poll_pidfd(test_name, pidfd); 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci time_t prog_time = time(NULL) - prog_start; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci ksft_print_msg("Time waited for child: %lu\n", prog_time); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci close(pidfd); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2) 47662306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed\n", test_name); 47762306a36Sopenharmony_ci else 47862306a36Sopenharmony_ci ksft_test_result_pass("%s test: Passed\n", test_name); 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic void *test_pidfd_poll_leader_exit_thread(void *priv) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci ksft_print_msg("Child Thread: starting. pid %d tid %ld ; and sleeping\n", 48462306a36Sopenharmony_ci getpid(), syscall(SYS_gettid)); 48562306a36Sopenharmony_ci sleep(CHILD_THREAD_MIN_WAIT); 48662306a36Sopenharmony_ci ksft_print_msg("Child Thread: DONE. pid %d tid %ld\n", getpid(), syscall(SYS_gettid)); 48762306a36Sopenharmony_ci return NULL; 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic time_t *child_exit_secs; 49162306a36Sopenharmony_cistatic int child_poll_leader_exit_test(void *args) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci pthread_t t1, t2; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci ksft_print_msg("Child: starting. pid %d tid %ld\n", getpid(), syscall(SYS_gettid)); 49662306a36Sopenharmony_ci pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL); 49762306a36Sopenharmony_ci pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* 50062306a36Sopenharmony_ci * glibc exit calls exit_group syscall, so explicity call exit only 50162306a36Sopenharmony_ci * so that only the group leader exits, leaving the threads alone. 50262306a36Sopenharmony_ci */ 50362306a36Sopenharmony_ci *child_exit_secs = time(NULL); 50462306a36Sopenharmony_ci syscall(SYS_exit, 0); 50562306a36Sopenharmony_ci /* Never reached, but appeases compiler thinking we should return. */ 50662306a36Sopenharmony_ci exit(0); 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic void test_pidfd_poll_leader_exit(int use_waitpid) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci int pid, pidfd = 0; 51262306a36Sopenharmony_ci int status, ret = 0; 51362306a36Sopenharmony_ci const char *test_name = "pidfd_poll check for premature notification on non-empty" 51462306a36Sopenharmony_ci "group leader exit"; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE, 51762306a36Sopenharmony_ci MAP_SHARED | MAP_ANONYMOUS, -1, 0); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (child_exit_secs == MAP_FAILED) 52062306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: mmap failed (errno %d)\n", 52162306a36Sopenharmony_ci test_name, errno); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci ksft_print_msg("Parent: pid: %d\n", getpid()); 52462306a36Sopenharmony_ci pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test); 52562306a36Sopenharmony_ci if (pid < 0) 52662306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n", 52762306a36Sopenharmony_ci test_name, pid, errno); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (use_waitpid) { 53262306a36Sopenharmony_ci ret = waitpid(pid, &status, 0); 53362306a36Sopenharmony_ci if (ret == -1) 53462306a36Sopenharmony_ci ksft_print_msg("Parent: error\n"); 53562306a36Sopenharmony_ci } else { 53662306a36Sopenharmony_ci /* 53762306a36Sopenharmony_ci * This sleep tests for the case where if the child exits, and is in 53862306a36Sopenharmony_ci * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll 53962306a36Sopenharmony_ci * doesn't prematurely return even though there are active threads 54062306a36Sopenharmony_ci */ 54162306a36Sopenharmony_ci sleep(1); 54262306a36Sopenharmony_ci poll_pidfd(test_name, pidfd); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (ret == pid) 54662306a36Sopenharmony_ci ksft_print_msg("Parent: Child process waited for.\n"); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci time_t since_child_exit = time(NULL) - *child_exit_secs; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci ksft_print_msg("Time since child exit: %lu\n", since_child_exit); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci close(pidfd); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (since_child_exit < CHILD_THREAD_MIN_WAIT || 55562306a36Sopenharmony_ci since_child_exit > CHILD_THREAD_MIN_WAIT + 2) 55662306a36Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed\n", test_name); 55762306a36Sopenharmony_ci else 55862306a36Sopenharmony_ci ksft_test_result_pass("%s test: Passed\n", test_name); 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ciint main(int argc, char **argv) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci ksft_print_header(); 56462306a36Sopenharmony_ci ksft_set_plan(8); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci test_pidfd_poll_exec(0); 56762306a36Sopenharmony_ci test_pidfd_poll_exec(1); 56862306a36Sopenharmony_ci test_pidfd_poll_leader_exit(0); 56962306a36Sopenharmony_ci test_pidfd_poll_leader_exit(1); 57062306a36Sopenharmony_ci test_pidfd_send_signal_syscall_support(); 57162306a36Sopenharmony_ci test_pidfd_send_signal_simple_success(); 57262306a36Sopenharmony_ci test_pidfd_send_signal_exited_fail(); 57362306a36Sopenharmony_ci test_pidfd_send_signal_recycled_pid_fail(); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci return ksft_exit_pass(); 57662306a36Sopenharmony_ci} 577