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