~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/pidfd/pidfd_test.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php