18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#define _GNU_SOURCE 48c2ecf20Sopenharmony_ci#include <errno.h> 58c2ecf20Sopenharmony_ci#include <fcntl.h> 68c2ecf20Sopenharmony_ci#include <linux/types.h> 78c2ecf20Sopenharmony_ci#include <pthread.h> 88c2ecf20Sopenharmony_ci#include <sched.h> 98c2ecf20Sopenharmony_ci#include <signal.h> 108c2ecf20Sopenharmony_ci#include <stdio.h> 118c2ecf20Sopenharmony_ci#include <stdbool.h> 128c2ecf20Sopenharmony_ci#include <stdlib.h> 138c2ecf20Sopenharmony_ci#include <string.h> 148c2ecf20Sopenharmony_ci#include <syscall.h> 158c2ecf20Sopenharmony_ci#include <sys/epoll.h> 168c2ecf20Sopenharmony_ci#include <sys/mman.h> 178c2ecf20Sopenharmony_ci#include <sys/mount.h> 188c2ecf20Sopenharmony_ci#include <sys/wait.h> 198c2ecf20Sopenharmony_ci#include <time.h> 208c2ecf20Sopenharmony_ci#include <unistd.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "pidfd.h" 238c2ecf20Sopenharmony_ci#include "../kselftest.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define str(s) _str(s) 268c2ecf20Sopenharmony_ci#define _str(s) #s 278c2ecf20Sopenharmony_ci#define CHILD_THREAD_MIN_WAIT 3 /* seconds */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define MAX_EVENTS 5 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic bool have_pidfd_send_signal; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *)) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci size_t stack_size = 1024; 368c2ecf20Sopenharmony_ci char *stack[1024] = { 0 }; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#ifdef __ia64__ 398c2ecf20Sopenharmony_ci return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd); 408c2ecf20Sopenharmony_ci#else 418c2ecf20Sopenharmony_ci return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd); 428c2ecf20Sopenharmony_ci#endif 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int signal_received; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic void set_signal_received_on_sigusr1(int sig) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci if (sig == SIGUSR1) 508c2ecf20Sopenharmony_ci signal_received = 1; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * Straightforward test to see whether pidfd_send_signal() works is to send 558c2ecf20Sopenharmony_ci * a signal to ourself. 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cistatic int test_pidfd_send_signal_simple_success(void) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci int pidfd, ret; 608c2ecf20Sopenharmony_ci const char *test_name = "pidfd_send_signal send SIGUSR1"; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (!have_pidfd_send_signal) { 638c2ecf20Sopenharmony_ci ksft_test_result_skip( 648c2ecf20Sopenharmony_ci "%s test: pidfd_send_signal() syscall not supported\n", 658c2ecf20Sopenharmony_ci test_name); 668c2ecf20Sopenharmony_ci return 0; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC); 708c2ecf20Sopenharmony_ci if (pidfd < 0) 718c2ecf20Sopenharmony_ci ksft_exit_fail_msg( 728c2ecf20Sopenharmony_ci "%s test: Failed to open process file descriptor\n", 738c2ecf20Sopenharmony_ci test_name); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci signal(SIGUSR1, set_signal_received_on_sigusr1); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci ret = sys_pidfd_send_signal(pidfd, SIGUSR1, NULL, 0); 788c2ecf20Sopenharmony_ci close(pidfd); 798c2ecf20Sopenharmony_ci if (ret < 0) 808c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to send signal\n", 818c2ecf20Sopenharmony_ci test_name); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (signal_received != 1) 848c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to receive signal\n", 858c2ecf20Sopenharmony_ci test_name); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci signal_received = 0; 888c2ecf20Sopenharmony_ci ksft_test_result_pass("%s test: Sent signal\n", test_name); 898c2ecf20Sopenharmony_ci return 0; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int test_pidfd_send_signal_exited_fail(void) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci int pidfd, ret, saved_errno; 958c2ecf20Sopenharmony_ci char buf[256]; 968c2ecf20Sopenharmony_ci pid_t pid; 978c2ecf20Sopenharmony_ci const char *test_name = "pidfd_send_signal signal exited process"; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (!have_pidfd_send_signal) { 1008c2ecf20Sopenharmony_ci ksft_test_result_skip( 1018c2ecf20Sopenharmony_ci "%s test: pidfd_send_signal() syscall not supported\n", 1028c2ecf20Sopenharmony_ci test_name); 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci pid = fork(); 1078c2ecf20Sopenharmony_ci if (pid < 0) 1088c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to create new process\n", 1098c2ecf20Sopenharmony_ci test_name); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (pid == 0) 1128c2ecf20Sopenharmony_ci _exit(EXIT_SUCCESS); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "/proc/%d", pid); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci (void)wait_for_pid(pid); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (pidfd < 0) 1218c2ecf20Sopenharmony_ci ksft_exit_fail_msg( 1228c2ecf20Sopenharmony_ci "%s test: Failed to open process file descriptor\n", 1238c2ecf20Sopenharmony_ci test_name); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); 1268c2ecf20Sopenharmony_ci saved_errno = errno; 1278c2ecf20Sopenharmony_ci close(pidfd); 1288c2ecf20Sopenharmony_ci if (ret == 0) 1298c2ecf20Sopenharmony_ci ksft_exit_fail_msg( 1308c2ecf20Sopenharmony_ci "%s test: Managed to send signal to process even though it should have failed\n", 1318c2ecf20Sopenharmony_ci test_name); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (saved_errno != ESRCH) 1348c2ecf20Sopenharmony_ci ksft_exit_fail_msg( 1358c2ecf20Sopenharmony_ci "%s test: Expected to receive ESRCH as errno value but received %d instead\n", 1368c2ecf20Sopenharmony_ci test_name, saved_errno); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci ksft_test_result_pass("%s test: Failed to send signal as expected\n", 1398c2ecf20Sopenharmony_ci test_name); 1408c2ecf20Sopenharmony_ci return 0; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* 1448c2ecf20Sopenharmony_ci * Maximum number of cycles we allow. This is equivalent to PID_MAX_DEFAULT. 1458c2ecf20Sopenharmony_ci * If users set a higher limit or we have cycled PIDFD_MAX_DEFAULT number of 1468c2ecf20Sopenharmony_ci * times then we skip the test to not go into an infinite loop or block for a 1478c2ecf20Sopenharmony_ci * long time. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci#define PIDFD_MAX_DEFAULT 0x8000 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic int test_pidfd_send_signal_recycled_pid_fail(void) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci int i, ret; 1548c2ecf20Sopenharmony_ci pid_t pid1; 1558c2ecf20Sopenharmony_ci const char *test_name = "pidfd_send_signal signal recycled pid"; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (!have_pidfd_send_signal) { 1588c2ecf20Sopenharmony_ci ksft_test_result_skip( 1598c2ecf20Sopenharmony_ci "%s test: pidfd_send_signal() syscall not supported\n", 1608c2ecf20Sopenharmony_ci test_name); 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci ret = unshare(CLONE_NEWPID); 1658c2ecf20Sopenharmony_ci if (ret < 0) { 1668c2ecf20Sopenharmony_ci if (errno == EPERM) { 1678c2ecf20Sopenharmony_ci ksft_test_result_skip("%s test: Unsharing pid namespace not permitted\n", 1688c2ecf20Sopenharmony_ci test_name); 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to unshare pid namespace\n", 1728c2ecf20Sopenharmony_ci test_name); 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci ret = unshare(CLONE_NEWNS); 1768c2ecf20Sopenharmony_ci if (ret < 0) { 1778c2ecf20Sopenharmony_ci if (errno == EPERM) { 1788c2ecf20Sopenharmony_ci ksft_test_result_skip("%s test: Unsharing mount namespace not permitted\n", 1798c2ecf20Sopenharmony_ci test_name); 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to unshare mount namespace\n", 1838c2ecf20Sopenharmony_ci test_name); 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0); 1878c2ecf20Sopenharmony_ci if (ret < 0) 1888c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to remount / private\n", 1898c2ecf20Sopenharmony_ci test_name); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* pid 1 in new pid namespace */ 1928c2ecf20Sopenharmony_ci pid1 = fork(); 1938c2ecf20Sopenharmony_ci if (pid1 < 0) 1948c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to create new process\n", 1958c2ecf20Sopenharmony_ci test_name); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (pid1 == 0) { 1988c2ecf20Sopenharmony_ci char buf[256]; 1998c2ecf20Sopenharmony_ci pid_t pid2; 2008c2ecf20Sopenharmony_ci int pidfd = -1; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci (void)umount2("/proc", MNT_DETACH); 2038c2ecf20Sopenharmony_ci ret = mount("proc", "/proc", "proc", 0, NULL); 2048c2ecf20Sopenharmony_ci if (ret < 0) 2058c2ecf20Sopenharmony_ci _exit(PIDFD_ERROR); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* grab pid PID_RECYCLE */ 2088c2ecf20Sopenharmony_ci for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) { 2098c2ecf20Sopenharmony_ci pid2 = fork(); 2108c2ecf20Sopenharmony_ci if (pid2 < 0) 2118c2ecf20Sopenharmony_ci _exit(PIDFD_ERROR); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (pid2 == 0) 2148c2ecf20Sopenharmony_ci _exit(PIDFD_PASS); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (pid2 == PID_RECYCLE) { 2178c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "/proc/%d", pid2); 2188c2ecf20Sopenharmony_ci ksft_print_msg("pid to recycle is %d\n", pid2); 2198c2ecf20Sopenharmony_ci pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (wait_for_pid(pid2)) 2238c2ecf20Sopenharmony_ci _exit(PIDFD_ERROR); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (pid2 >= PID_RECYCLE) 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* 2308c2ecf20Sopenharmony_ci * We want to be as predictable as we can so if we haven't been 2318c2ecf20Sopenharmony_ci * able to grab pid PID_RECYCLE skip the test. 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_ci if (pid2 != PID_RECYCLE) { 2348c2ecf20Sopenharmony_ci /* skip test */ 2358c2ecf20Sopenharmony_ci close(pidfd); 2368c2ecf20Sopenharmony_ci _exit(PIDFD_SKIP); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (pidfd < 0) 2408c2ecf20Sopenharmony_ci _exit(PIDFD_ERROR); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) { 2438c2ecf20Sopenharmony_ci char c; 2448c2ecf20Sopenharmony_ci int pipe_fds[2]; 2458c2ecf20Sopenharmony_ci pid_t recycled_pid; 2468c2ecf20Sopenharmony_ci int child_ret = PIDFD_PASS; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci ret = pipe2(pipe_fds, O_CLOEXEC); 2498c2ecf20Sopenharmony_ci if (ret < 0) 2508c2ecf20Sopenharmony_ci _exit(PIDFD_ERROR); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci recycled_pid = fork(); 2538c2ecf20Sopenharmony_ci if (recycled_pid < 0) 2548c2ecf20Sopenharmony_ci _exit(PIDFD_ERROR); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (recycled_pid == 0) { 2578c2ecf20Sopenharmony_ci close(pipe_fds[1]); 2588c2ecf20Sopenharmony_ci (void)read(pipe_fds[0], &c, 1); 2598c2ecf20Sopenharmony_ci close(pipe_fds[0]); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci _exit(PIDFD_PASS); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* 2658c2ecf20Sopenharmony_ci * Stop the child so we can inspect whether we have 2668c2ecf20Sopenharmony_ci * recycled pid PID_RECYCLE. 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_ci close(pipe_fds[0]); 2698c2ecf20Sopenharmony_ci ret = kill(recycled_pid, SIGSTOP); 2708c2ecf20Sopenharmony_ci close(pipe_fds[1]); 2718c2ecf20Sopenharmony_ci if (ret) { 2728c2ecf20Sopenharmony_ci (void)wait_for_pid(recycled_pid); 2738c2ecf20Sopenharmony_ci _exit(PIDFD_ERROR); 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* 2778c2ecf20Sopenharmony_ci * We have recycled the pid. Try to signal it. This 2788c2ecf20Sopenharmony_ci * needs to fail since this is a different process than 2798c2ecf20Sopenharmony_ci * the one the pidfd refers to. 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_ci if (recycled_pid == PID_RECYCLE) { 2828c2ecf20Sopenharmony_ci ret = sys_pidfd_send_signal(pidfd, SIGCONT, 2838c2ecf20Sopenharmony_ci NULL, 0); 2848c2ecf20Sopenharmony_ci if (ret && errno == ESRCH) 2858c2ecf20Sopenharmony_ci child_ret = PIDFD_XFAIL; 2868c2ecf20Sopenharmony_ci else 2878c2ecf20Sopenharmony_ci child_ret = PIDFD_FAIL; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* let the process move on */ 2918c2ecf20Sopenharmony_ci ret = kill(recycled_pid, SIGCONT); 2928c2ecf20Sopenharmony_ci if (ret) 2938c2ecf20Sopenharmony_ci (void)kill(recycled_pid, SIGKILL); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (wait_for_pid(recycled_pid)) 2968c2ecf20Sopenharmony_ci _exit(PIDFD_ERROR); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci switch (child_ret) { 2998c2ecf20Sopenharmony_ci case PIDFD_FAIL: 3008c2ecf20Sopenharmony_ci /* fallthrough */ 3018c2ecf20Sopenharmony_ci case PIDFD_XFAIL: 3028c2ecf20Sopenharmony_ci _exit(child_ret); 3038c2ecf20Sopenharmony_ci case PIDFD_PASS: 3048c2ecf20Sopenharmony_ci break; 3058c2ecf20Sopenharmony_ci default: 3068c2ecf20Sopenharmony_ci /* not reached */ 3078c2ecf20Sopenharmony_ci _exit(PIDFD_ERROR); 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* 3118c2ecf20Sopenharmony_ci * If the user set a custom pid_max limit we could be 3128c2ecf20Sopenharmony_ci * in the millions. 3138c2ecf20Sopenharmony_ci * Skip the test in this case. 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci if (recycled_pid > PIDFD_MAX_DEFAULT) 3168c2ecf20Sopenharmony_ci _exit(PIDFD_SKIP); 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* failed to recycle pid */ 3208c2ecf20Sopenharmony_ci _exit(PIDFD_SKIP); 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci ret = wait_for_pid(pid1); 3248c2ecf20Sopenharmony_ci switch (ret) { 3258c2ecf20Sopenharmony_ci case PIDFD_FAIL: 3268c2ecf20Sopenharmony_ci ksft_exit_fail_msg( 3278c2ecf20Sopenharmony_ci "%s test: Managed to signal recycled pid %d\n", 3288c2ecf20Sopenharmony_ci test_name, PID_RECYCLE); 3298c2ecf20Sopenharmony_ci case PIDFD_PASS: 3308c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to recycle pid %d\n", 3318c2ecf20Sopenharmony_ci test_name, PID_RECYCLE); 3328c2ecf20Sopenharmony_ci case PIDFD_SKIP: 3338c2ecf20Sopenharmony_ci ksft_test_result_skip("%s test: Skipping test\n", test_name); 3348c2ecf20Sopenharmony_ci ret = 0; 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci case PIDFD_XFAIL: 3378c2ecf20Sopenharmony_ci ksft_test_result_pass( 3388c2ecf20Sopenharmony_ci "%s test: Failed to signal recycled pid as expected\n", 3398c2ecf20Sopenharmony_ci test_name); 3408c2ecf20Sopenharmony_ci ret = 0; 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci default /* PIDFD_ERROR */: 3438c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Error while running tests\n", 3448c2ecf20Sopenharmony_ci test_name); 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci return ret; 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic int test_pidfd_send_signal_syscall_support(void) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci int pidfd, ret; 3538c2ecf20Sopenharmony_ci const char *test_name = "pidfd_send_signal check for support"; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC); 3568c2ecf20Sopenharmony_ci if (pidfd < 0) 3578c2ecf20Sopenharmony_ci ksft_exit_fail_msg( 3588c2ecf20Sopenharmony_ci "%s test: Failed to open process file descriptor\n", 3598c2ecf20Sopenharmony_ci test_name); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); 3628c2ecf20Sopenharmony_ci if (ret < 0) { 3638c2ecf20Sopenharmony_ci if (errno == ENOSYS) { 3648c2ecf20Sopenharmony_ci ksft_test_result_skip( 3658c2ecf20Sopenharmony_ci "%s test: pidfd_send_signal() syscall not supported\n", 3668c2ecf20Sopenharmony_ci test_name); 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to send signal\n", 3708c2ecf20Sopenharmony_ci test_name); 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci have_pidfd_send_signal = true; 3748c2ecf20Sopenharmony_ci close(pidfd); 3758c2ecf20Sopenharmony_ci ksft_test_result_pass( 3768c2ecf20Sopenharmony_ci "%s test: pidfd_send_signal() syscall is supported. Tests can be executed\n", 3778c2ecf20Sopenharmony_ci test_name); 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic void *test_pidfd_poll_exec_thread(void *priv) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci ksft_print_msg("Child Thread: starting. pid %d tid %ld ; and sleeping\n", 3848c2ecf20Sopenharmony_ci getpid(), syscall(SYS_gettid)); 3858c2ecf20Sopenharmony_ci ksft_print_msg("Child Thread: doing exec of sleep\n"); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci execl("/bin/sleep", "sleep", str(CHILD_THREAD_MIN_WAIT), (char *)NULL); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci ksft_print_msg("Child Thread: DONE. pid %d tid %ld\n", 3908c2ecf20Sopenharmony_ci getpid(), syscall(SYS_gettid)); 3918c2ecf20Sopenharmony_ci return NULL; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic void poll_pidfd(const char *test_name, int pidfd) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci int c; 3978c2ecf20Sopenharmony_ci int epoll_fd = epoll_create1(EPOLL_CLOEXEC); 3988c2ecf20Sopenharmony_ci struct epoll_event event, events[MAX_EVENTS]; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (epoll_fd == -1) 4018c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor " 4028c2ecf20Sopenharmony_ci "(errno %d)\n", 4038c2ecf20Sopenharmony_ci test_name, errno); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci event.events = EPOLLIN; 4068c2ecf20Sopenharmony_ci event.data.fd = pidfd; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) { 4098c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed to add epoll file descriptor " 4108c2ecf20Sopenharmony_ci "(errno %d)\n", 4118c2ecf20Sopenharmony_ci test_name, errno); 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000); 4158c2ecf20Sopenharmony_ci if (c != 1 || !(events[0].events & EPOLLIN)) 4168c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x) ", 4178c2ecf20Sopenharmony_ci "(errno %d)\n", 4188c2ecf20Sopenharmony_ci test_name, c, events[0].events, errno); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci close(epoll_fd); 4218c2ecf20Sopenharmony_ci return; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int child_poll_exec_test(void *args) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci pthread_t t1; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci ksft_print_msg("Child (pidfd): starting. pid %d tid %ld\n", getpid(), 4308c2ecf20Sopenharmony_ci syscall(SYS_gettid)); 4318c2ecf20Sopenharmony_ci pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL); 4328c2ecf20Sopenharmony_ci /* 4338c2ecf20Sopenharmony_ci * Exec in the non-leader thread will destroy the leader immediately. 4348c2ecf20Sopenharmony_ci * If the wait in the parent returns too soon, the test fails. 4358c2ecf20Sopenharmony_ci */ 4368c2ecf20Sopenharmony_ci while (1) 4378c2ecf20Sopenharmony_ci sleep(1); 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic void test_pidfd_poll_exec(int use_waitpid) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci int pid, pidfd = 0; 4438c2ecf20Sopenharmony_ci int status, ret; 4448c2ecf20Sopenharmony_ci time_t prog_start = time(NULL); 4458c2ecf20Sopenharmony_ci const char *test_name = "pidfd_poll check for premature notification on child thread exec"; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci ksft_print_msg("Parent: pid: %d\n", getpid()); 4488c2ecf20Sopenharmony_ci pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test); 4498c2ecf20Sopenharmony_ci if (pid < 0) 4508c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n", 4518c2ecf20Sopenharmony_ci test_name, pid, errno); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (use_waitpid) { 4568c2ecf20Sopenharmony_ci ret = waitpid(pid, &status, 0); 4578c2ecf20Sopenharmony_ci if (ret == -1) 4588c2ecf20Sopenharmony_ci ksft_print_msg("Parent: error\n"); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (ret == pid) 4618c2ecf20Sopenharmony_ci ksft_print_msg("Parent: Child process waited for.\n"); 4628c2ecf20Sopenharmony_ci } else { 4638c2ecf20Sopenharmony_ci poll_pidfd(test_name, pidfd); 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci time_t prog_time = time(NULL) - prog_start; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci ksft_print_msg("Time waited for child: %lu\n", prog_time); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci close(pidfd); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2) 4738c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed\n", test_name); 4748c2ecf20Sopenharmony_ci else 4758c2ecf20Sopenharmony_ci ksft_test_result_pass("%s test: Passed\n", test_name); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic void *test_pidfd_poll_leader_exit_thread(void *priv) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci ksft_print_msg("Child Thread: starting. pid %d tid %ld ; and sleeping\n", 4818c2ecf20Sopenharmony_ci getpid(), syscall(SYS_gettid)); 4828c2ecf20Sopenharmony_ci sleep(CHILD_THREAD_MIN_WAIT); 4838c2ecf20Sopenharmony_ci ksft_print_msg("Child Thread: DONE. pid %d tid %ld\n", getpid(), syscall(SYS_gettid)); 4848c2ecf20Sopenharmony_ci return NULL; 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic time_t *child_exit_secs; 4888c2ecf20Sopenharmony_cistatic int child_poll_leader_exit_test(void *args) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci pthread_t t1, t2; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci ksft_print_msg("Child: starting. pid %d tid %ld\n", getpid(), syscall(SYS_gettid)); 4938c2ecf20Sopenharmony_ci pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL); 4948c2ecf20Sopenharmony_ci pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* 4978c2ecf20Sopenharmony_ci * glibc exit calls exit_group syscall, so explicity call exit only 4988c2ecf20Sopenharmony_ci * so that only the group leader exits, leaving the threads alone. 4998c2ecf20Sopenharmony_ci */ 5008c2ecf20Sopenharmony_ci *child_exit_secs = time(NULL); 5018c2ecf20Sopenharmony_ci syscall(SYS_exit, 0); 5028c2ecf20Sopenharmony_ci /* Never reached, but appeases compiler thinking we should return. */ 5038c2ecf20Sopenharmony_ci exit(0); 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic void test_pidfd_poll_leader_exit(int use_waitpid) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci int pid, pidfd = 0; 5098c2ecf20Sopenharmony_ci int status, ret = 0; 5108c2ecf20Sopenharmony_ci const char *test_name = "pidfd_poll check for premature notification on non-empty" 5118c2ecf20Sopenharmony_ci "group leader exit"; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE, 5148c2ecf20Sopenharmony_ci MAP_SHARED | MAP_ANONYMOUS, -1, 0); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (child_exit_secs == MAP_FAILED) 5178c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: mmap failed (errno %d)\n", 5188c2ecf20Sopenharmony_ci test_name, errno); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci ksft_print_msg("Parent: pid: %d\n", getpid()); 5218c2ecf20Sopenharmony_ci pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test); 5228c2ecf20Sopenharmony_ci if (pid < 0) 5238c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n", 5248c2ecf20Sopenharmony_ci test_name, pid, errno); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (use_waitpid) { 5298c2ecf20Sopenharmony_ci ret = waitpid(pid, &status, 0); 5308c2ecf20Sopenharmony_ci if (ret == -1) 5318c2ecf20Sopenharmony_ci ksft_print_msg("Parent: error\n"); 5328c2ecf20Sopenharmony_ci } else { 5338c2ecf20Sopenharmony_ci /* 5348c2ecf20Sopenharmony_ci * This sleep tests for the case where if the child exits, and is in 5358c2ecf20Sopenharmony_ci * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll 5368c2ecf20Sopenharmony_ci * doesn't prematurely return even though there are active threads 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_ci sleep(1); 5398c2ecf20Sopenharmony_ci poll_pidfd(test_name, pidfd); 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (ret == pid) 5438c2ecf20Sopenharmony_ci ksft_print_msg("Parent: Child process waited for.\n"); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci time_t since_child_exit = time(NULL) - *child_exit_secs; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci ksft_print_msg("Time since child exit: %lu\n", since_child_exit); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci close(pidfd); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (since_child_exit < CHILD_THREAD_MIN_WAIT || 5528c2ecf20Sopenharmony_ci since_child_exit > CHILD_THREAD_MIN_WAIT + 2) 5538c2ecf20Sopenharmony_ci ksft_exit_fail_msg("%s test: Failed\n", test_name); 5548c2ecf20Sopenharmony_ci else 5558c2ecf20Sopenharmony_ci ksft_test_result_pass("%s test: Passed\n", test_name); 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ciint main(int argc, char **argv) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci ksft_print_header(); 5618c2ecf20Sopenharmony_ci ksft_set_plan(8); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci test_pidfd_poll_exec(0); 5648c2ecf20Sopenharmony_ci test_pidfd_poll_exec(1); 5658c2ecf20Sopenharmony_ci test_pidfd_poll_leader_exit(0); 5668c2ecf20Sopenharmony_ci test_pidfd_poll_leader_exit(1); 5678c2ecf20Sopenharmony_ci test_pidfd_send_signal_syscall_support(); 5688c2ecf20Sopenharmony_ci test_pidfd_send_signal_simple_success(); 5698c2ecf20Sopenharmony_ci test_pidfd_send_signal_exited_fail(); 5708c2ecf20Sopenharmony_ci test_pidfd_send_signal_recycled_pid_fail(); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci return ksft_exit_pass(); 5738c2ecf20Sopenharmony_ci} 574