File Index
Files and directories
Sign in
FILE

pidfd_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/pidfd/pidfd_test.c C
  1/* SPDX-License-Identifier: GPL-2.0 */
  2
  3#define _GNU_SOURCE
  4#include <errno.h>
  5#include <fcntl.h>
  6#include <linux/types.h>
  7#include <pthread.h>
  8#include <sched.h>
  9#include <signal.h>
 10#include <stdio.h>
 11#include <stdbool.h>
 12#include <stdlib.h>
 13#include <string.h>
 14#include <syscall.h>
 15#include <sys/epoll.h>
 16#include <sys/mman.h>
 17#include <sys/mount.h>
 18#include <sys/wait.h>
 19#include <time.h>
 20#include <unistd.h>
 21
 22#include "pidfd.h"
 23#include "kselftest.h"
 24
 25#define str(s) _str(s)
 26#define _str(s) #s
 27#define CHILD_THREAD_MIN_WAIT 3 /* seconds */
 28
 29#define MAX_EVENTS 5
 30
 31static bool have_pidfd_send_signal;
 32
 33static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
 34{
 35	size_t stack_size = 1024;
 36	char *stack[1024] = { 0 };
 37
 38#ifdef __ia64__
 39	return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd);
 40#else
 41	return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd);
 42#endif
 43}
 44
 45static pthread_t signal_received;
 46
 47static void set_signal_received_on_sigusr1(int sig)
 48{
 49	if (sig == SIGUSR1)
 50		signal_received = pthread_self();
 51}
 52
 53static int send_signal(int pidfd)
 54{
 55	int ret = 0;
 56
 57	if (sys_pidfd_send_signal(pidfd, SIGUSR1, NULL, 0) < 0) {
 58		ret = -EINVAL;
 59		goto exit;
 60	}
 61
 62	if (signal_received != pthread_self()) {
 63		ret = -EINVAL;
 64		goto exit;
 65	}
 66
 67exit:
 68	signal_received = 0;
 69	return ret;
 70}
 71
 72static void *send_signal_worker(void *arg)
 73{
 74	int pidfd = (int)(intptr_t)arg;
 75	int ret;
 76
 77	/* We forward any errors for the caller to handle. */
 78	ret = send_signal(pidfd);
 79	return (void *)(intptr_t)ret;
 80}
 81
 82/*
 83 * Straightforward test to see whether pidfd_send_signal() works is to send
 84 * a signal to ourself.
 85 */
 86static int test_pidfd_send_signal_simple_success(void)
 87{
 88	int pidfd;
 89	const char *test_name = "pidfd_send_signal send SIGUSR1";
 90	pthread_t thread;
 91	void *thread_res;
 92	int err;
 93
 94	if (!have_pidfd_send_signal) {
 95		ksft_test_result_skip(
 96			"%s test: pidfd_send_signal() syscall not supported\n",
 97			test_name);
 98		return 0;
 99	}
100
101	signal(SIGUSR1, set_signal_received_on_sigusr1);
102
103	/* Try sending a signal to ourselves via /proc/self. */
104	pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC);
105	if (pidfd < 0)
106		ksft_exit_fail_msg(
107			"%s test: Failed to open process file descriptor\n",
108			test_name);
109	err = send_signal(pidfd);
110	if (err)
111		ksft_exit_fail_msg(
112			"%s test: Error %d on sending pidfd signal\n",
113			test_name, err);
114	close(pidfd);
115
116	/* Now try the same thing only using PIDFD_SELF_THREAD_GROUP. */
117	err = send_signal(PIDFD_SELF_THREAD_GROUP);
118	if (err)
119		ksft_exit_fail_msg(
120			"%s test: Error %d on PIDFD_SELF_THREAD_GROUP signal\n",
121			test_name, err);
122
123	/*
124	 * Now try the same thing in a thread and assert thread ID is equal to
125	 * worker thread ID.
126	 */
127	if (pthread_create(&thread, NULL, send_signal_worker,
128			   (void *)(intptr_t)PIDFD_SELF_THREAD))
129		ksft_exit_fail_msg("%s test: Failed to create thread\n",
130				   test_name);
131	if (pthread_join(thread, &thread_res))
132		ksft_exit_fail_msg("%s test: Failed to join thread\n",
133				   test_name);
134	err = (int)(intptr_t)thread_res;
135	if (err)
136		ksft_exit_fail_msg(
137			"%s test: Error %d on PIDFD_SELF_THREAD signal\n",
138			test_name, err);
139
140	ksft_test_result_pass("%s test: Sent signal\n", test_name);
141	return 0;
142}
143
144static int test_pidfd_send_signal_exited_fail(void)
145{
146	int pidfd, ret, saved_errno;
147	char buf[256];
148	pid_t pid;
149	const char *test_name = "pidfd_send_signal signal exited process";
150
151	if (!have_pidfd_send_signal) {
152		ksft_test_result_skip(
153			"%s test: pidfd_send_signal() syscall not supported\n",
154			test_name);
155		return 0;
156	}
157
158	pid = fork();
159	if (pid < 0)
160		ksft_exit_fail_msg("%s test: Failed to create new process\n",
161				   test_name);
162
163	if (pid == 0)
164		_exit(EXIT_SUCCESS);
165
166	snprintf(buf, sizeof(buf), "/proc/%d", pid);
167
168	pidfd = open(buf, O_DIRECTORY | O_CLOEXEC);
169
170	ret = wait_for_pid(pid);
171	ksft_print_msg("waitpid WEXITSTATUS=%d\n", ret);
172
173	if (pidfd < 0)
174		ksft_exit_fail_msg(
175			"%s test: Failed to open process file descriptor\n",
176			test_name);
177
178	ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0);
179	saved_errno = errno;
180	close(pidfd);
181	if (ret == 0)
182		ksft_exit_fail_msg(
183			"%s test: Managed to send signal to process even though it should have failed\n",
184			test_name);
185
186	if (saved_errno != ESRCH)
187		ksft_exit_fail_msg(
188			"%s test: Expected to receive ESRCH as errno value but received %d instead\n",
189			test_name, saved_errno);
190
191	ksft_test_result_pass("%s test: Failed to send signal as expected\n",
192			      test_name);
193	return 0;
194}
195
196/*
197 * Maximum number of cycles we allow. This is equivalent to PID_MAX_DEFAULT.
198 * If users set a higher limit or we have cycled PIDFD_MAX_DEFAULT number of
199 * times then we skip the test to not go into an infinite loop or block for a
200 * long time.
201 */
202#define PIDFD_MAX_DEFAULT 0x8000
203
204static int test_pidfd_send_signal_recycled_pid_fail(void)
205{
206	int i, ret;
207	pid_t pid1;
208	const char *test_name = "pidfd_send_signal signal recycled pid";
209
210	if (!have_pidfd_send_signal) {
211		ksft_test_result_skip(
212			"%s test: pidfd_send_signal() syscall not supported\n",
213			test_name);
214		return 0;
215	}
216
217	ret = unshare(CLONE_NEWPID);
218	if (ret < 0) {
219		if (errno == EPERM) {
220			ksft_test_result_skip("%s test: Unsharing pid namespace not permitted\n",
221					      test_name);
222			return 0;
223		}
224		ksft_exit_fail_msg("%s test: Failed to unshare pid namespace\n",
225				   test_name);
226	}
227
228	ret = unshare(CLONE_NEWNS);
229	if (ret < 0) {
230		if (errno == EPERM) {
231			ksft_test_result_skip("%s test: Unsharing mount namespace not permitted\n",
232					      test_name);
233			return 0;
234		}
235		ksft_exit_fail_msg("%s test: Failed to unshare mount namespace\n",
236				   test_name);
237	}
238
239	ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
240	if (ret < 0)
241		ksft_exit_fail_msg("%s test: Failed to remount / private\n",
242				   test_name);
243
244	/* pid 1 in new pid namespace */
245	pid1 = fork();
246	if (pid1 < 0)
247		ksft_exit_fail_msg("%s test: Failed to create new process\n",
248				   test_name);
249
250	if (pid1 == 0) {
251		char buf[256];
252		pid_t pid2;
253		int pidfd = -1;
254
255		(void)umount2("/proc", MNT_DETACH);
256		ret = mount("proc", "/proc", "proc", 0, NULL);
257		if (ret < 0)
258			_exit(PIDFD_ERROR);
259
260		/* grab pid PID_RECYCLE */
261		for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) {
262			pid2 = fork();
263			if (pid2 < 0)
264				_exit(PIDFD_ERROR);
265
266			if (pid2 == 0)
267				_exit(PIDFD_PASS);
268
269			if (pid2 == PID_RECYCLE) {
270				snprintf(buf, sizeof(buf), "/proc/%d", pid2);
271				ksft_print_msg("pid to recycle is %d\n", pid2);
272				pidfd = open(buf, O_DIRECTORY | O_CLOEXEC);
273			}
274
275			if (wait_for_pid(pid2))
276				_exit(PIDFD_ERROR);
277
278			if (pid2 >= PID_RECYCLE)
279				break;
280		}
281
282		/*
283		 * We want to be as predictable as we can so if we haven't been
284		 * able to grab pid PID_RECYCLE skip the test.
285		 */
286		if (pid2 != PID_RECYCLE) {
287			/* skip test */
288			close(pidfd);
289			_exit(PIDFD_SKIP);
290		}
291
292		if (pidfd < 0)
293			_exit(PIDFD_ERROR);
294
295		for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) {
296			char c;
297			int pipe_fds[2];
298			pid_t recycled_pid;
299			int child_ret = PIDFD_PASS;
300
301			ret = pipe2(pipe_fds, O_CLOEXEC);
302			if (ret < 0)
303				_exit(PIDFD_ERROR);
304
305			recycled_pid = fork();
306			if (recycled_pid < 0)
307				_exit(PIDFD_ERROR);
308
309			if (recycled_pid == 0) {
310				close(pipe_fds[1]);
311				(void)read(pipe_fds[0], &c, 1);
312				close(pipe_fds[0]);
313
314				_exit(PIDFD_PASS);
315			}
316
317			/*
318			 * Stop the child so we can inspect whether we have
319			 * recycled pid PID_RECYCLE.
320			 */
321			close(pipe_fds[0]);
322			ret = kill(recycled_pid, SIGSTOP);
323			close(pipe_fds[1]);
324			if (ret) {
325				(void)wait_for_pid(recycled_pid);
326				_exit(PIDFD_ERROR);
327			}
328
329			/*
330			 * We have recycled the pid. Try to signal it. This
331			 * needs to fail since this is a different process than
332			 * the one the pidfd refers to.
333			 */
334			if (recycled_pid == PID_RECYCLE) {
335				ret = sys_pidfd_send_signal(pidfd, SIGCONT,
336							    NULL, 0);
337				if (ret && errno == ESRCH)
338					child_ret = PIDFD_XFAIL;
339				else
340					child_ret = PIDFD_FAIL;
341			}
342
343			/* let the process move on */
344			ret = kill(recycled_pid, SIGCONT);
345			if (ret)
346				(void)kill(recycled_pid, SIGKILL);
347
348			if (wait_for_pid(recycled_pid))
349				_exit(PIDFD_ERROR);
350
351			switch (child_ret) {
352			case PIDFD_FAIL:
353				/* fallthrough */
354			case PIDFD_XFAIL:
355				_exit(child_ret);
356			case PIDFD_PASS:
357				break;
358			default:
359				/* not reached */
360				_exit(PIDFD_ERROR);
361			}
362
363			/*
364			 * If the user set a custom pid_max limit we could be
365			 * in the millions.
366			 * Skip the test in this case.
367			 */
368			if (recycled_pid > PIDFD_MAX_DEFAULT)
369				_exit(PIDFD_SKIP);
370		}
371
372		/* failed to recycle pid */
373		_exit(PIDFD_SKIP);
374	}
375
376	ret = wait_for_pid(pid1);
377	switch (ret) {
378	case PIDFD_FAIL:
379		ksft_exit_fail_msg(
380			"%s test: Managed to signal recycled pid %d\n",
381			test_name, PID_RECYCLE);
382	case PIDFD_PASS:
383		ksft_exit_fail_msg("%s test: Failed to recycle pid %d\n",
384				   test_name, PID_RECYCLE);
385	case PIDFD_SKIP:
386		ksft_test_result_skip("%s test: Skipping test\n", test_name);
387		ret = 0;
388		break;
389	case PIDFD_XFAIL:
390		ksft_test_result_pass(
391			"%s test: Failed to signal recycled pid as expected\n",
392			test_name);
393		ret = 0;
394		break;
395	default /* PIDFD_ERROR */:
396		ksft_exit_fail_msg("%s test: Error while running tests\n",
397				   test_name);
398	}
399
400	return ret;
401}
402
403static int test_pidfd_send_signal_syscall_support(void)
404{
405	int pidfd, ret;
406	const char *test_name = "pidfd_send_signal check for support";
407
408	pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC);
409	if (pidfd < 0)
410		ksft_exit_fail_msg(
411			"%s test: Failed to open process file descriptor\n",
412			test_name);
413
414	ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0);
415	if (ret < 0) {
416		if (errno == ENOSYS) {
417			ksft_test_result_skip(
418				"%s test: pidfd_send_signal() syscall not supported\n",
419				test_name);
420			return 0;
421		}
422		ksft_exit_fail_msg("%s test: Failed to send signal\n",
423				   test_name);
424	}
425
426	have_pidfd_send_signal = true;
427	close(pidfd);
428	ksft_test_result_pass(
429		"%s test: pidfd_send_signal() syscall is supported. Tests can be executed\n",
430		test_name);
431	return 0;
432}
433
434static void *test_pidfd_poll_exec_thread(void *priv)
435{
436	ksft_print_msg("Child Thread: starting. pid %d tid %ld ; and sleeping\n",
437			getpid(), syscall(SYS_gettid));
438	ksft_print_msg("Child Thread: doing exec of sleep\n");
439
440	execl("/bin/sleep", "sleep", str(CHILD_THREAD_MIN_WAIT), (char *)NULL);
441
442	ksft_print_msg("Child Thread: DONE. pid %d tid %ld\n",
443			getpid(), syscall(SYS_gettid));
444	return NULL;
445}
446
447static void poll_pidfd(const char *test_name, int pidfd)
448{
449	int c;
450	int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
451	struct epoll_event event, events[MAX_EVENTS];
452
453	if (epoll_fd == -1)
454		ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor "
455				   "(errno %d)\n",
456				   test_name, errno);
457
458	event.events = EPOLLIN;
459	event.data.fd = pidfd;
460
461	if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) {
462		ksft_exit_fail_msg("%s test: Failed to add epoll file descriptor "
463				   "(errno %d)\n",
464				   test_name, errno);
465	}
466
467	c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000);
468	if (c != 1 || !(events[0].events & EPOLLIN))
469		ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x) "
470				   "(errno %d)\n",
471				   test_name, c, events[0].events, errno);
472
473	close(epoll_fd);
474	return;
475
476}
477
478static int child_poll_exec_test(void *args)
479{
480	pthread_t t1;
481
482	ksft_print_msg("Child (pidfd): starting. pid %d tid %ld\n", getpid(),
483			syscall(SYS_gettid));
484	pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL);
485	/*
486	 * Exec in the non-leader thread will destroy the leader immediately.
487	 * If the wait in the parent returns too soon, the test fails.
488	 */
489	while (1)
490		sleep(1);
491
492	return 0;
493}
494
495static void test_pidfd_poll_exec(int use_waitpid)
496{
497	int pid, pidfd = 0;
498	int status, ret;
499	time_t prog_start = time(NULL);
500	const char *test_name = "pidfd_poll check for premature notification on child thread exec";
501
502	ksft_print_msg("Parent: pid: %d\n", getpid());
503	pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test);
504	if (pid < 0)
505		ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n",
506				   test_name, pid, errno);
507
508	ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid);
509
510	if (use_waitpid) {
511		ret = waitpid(pid, &status, 0);
512		if (ret == -1)
513			ksft_print_msg("Parent: error\n");
514
515		if (ret == pid)
516			ksft_print_msg("Parent: Child process waited for.\n");
517	} else {
518		poll_pidfd(test_name, pidfd);
519	}
520
521	time_t prog_time = time(NULL) - prog_start;
522
523	ksft_print_msg("Time waited for child: %lu\n", prog_time);
524
525	close(pidfd);
526
527	if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2)
528		ksft_exit_fail_msg("%s test: Failed\n", test_name);
529	else
530		ksft_test_result_pass("%s test: Passed\n", test_name);
531}
532
533static void *test_pidfd_poll_leader_exit_thread(void *priv)
534{
535	ksft_print_msg("Child Thread: starting. pid %d tid %ld ; and sleeping\n",
536			getpid(), syscall(SYS_gettid));
537	sleep(CHILD_THREAD_MIN_WAIT);
538	ksft_print_msg("Child Thread: DONE. pid %d tid %ld\n", getpid(), syscall(SYS_gettid));
539	return NULL;
540}
541
542static time_t *child_exit_secs;
543static int child_poll_leader_exit_test(void *args)
544{
545	pthread_t t1, t2;
546
547	ksft_print_msg("Child: starting. pid %d tid %ld\n", getpid(), syscall(SYS_gettid));
548	pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL);
549	pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL);
550
551	/*
552	 * glibc exit calls exit_group syscall, so explicitly call exit only
553	 * so that only the group leader exits, leaving the threads alone.
554	 */
555	*child_exit_secs = time(NULL);
556	syscall(SYS_exit, 0);
557	/* Never reached, but appeases compiler thinking we should return. */
558	exit(0);
559}
560
561static void test_pidfd_poll_leader_exit(int use_waitpid)
562{
563	int pid, pidfd = 0;
564	int status, ret = 0;
565	const char *test_name = "pidfd_poll check for premature notification on non-empty"
566				"group leader exit";
567
568	child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE,
569			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
570
571	if (child_exit_secs == MAP_FAILED)
572		ksft_exit_fail_msg("%s test: mmap failed (errno %d)\n",
573				   test_name, errno);
574
575	ksft_print_msg("Parent: pid: %d\n", getpid());
576	pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test);
577	if (pid < 0)
578		ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n",
579				   test_name, pid, errno);
580
581	ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid);
582
583	if (use_waitpid) {
584		ret = waitpid(pid, &status, 0);
585		if (ret == -1)
586			ksft_print_msg("Parent: error\n");
587	} else {
588		/*
589		 * This sleep tests for the case where if the child exits, and is in
590		 * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll
591		 * doesn't prematurely return even though there are active threads
592		 */
593		sleep(1);
594		poll_pidfd(test_name, pidfd);
595	}
596
597	if (ret == pid)
598		ksft_print_msg("Parent: Child process waited for.\n");
599
600	time_t since_child_exit = time(NULL) - *child_exit_secs;
601
602	ksft_print_msg("Time since child exit: %lu\n", since_child_exit);
603
604	close(pidfd);
605
606	if (since_child_exit < CHILD_THREAD_MIN_WAIT ||
607			since_child_exit > CHILD_THREAD_MIN_WAIT + 2)
608		ksft_exit_fail_msg("%s test: Failed\n", test_name);
609	else
610		ksft_test_result_pass("%s test: Passed\n", test_name);
611}
612
613int main(int argc, char **argv)
614{
615	ksft_print_header();
616	ksft_set_plan(8);
617
618	test_pidfd_poll_exec(0);
619	test_pidfd_poll_exec(1);
620	test_pidfd_poll_leader_exit(0);
621	test_pidfd_poll_leader_exit(1);
622	test_pidfd_send_signal_syscall_support();
623	test_pidfd_send_signal_simple_success();
624	test_pidfd_send_signal_exited_fail();
625	test_pidfd_send_signal_recycled_pid_fail();
626
627	ksft_exit_pass();
628}
~/ Read-only file preview.