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