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 | msg: "%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 | msg: "%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(msg: "%s test: Failed to send signal\n" , |
81 | test_name); |
82 | |
83 | if (signal_received != 1) |
84 | ksft_exit_fail_msg(msg: "%s test: Failed to receive signal\n" , |
85 | test_name); |
86 | |
87 | signal_received = 0; |
88 | ksft_test_result_pass(msg: "%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 | msg: "%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(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(msg: "waitpid WEXITSTATUS=%d\n" , ret); |
120 | |
121 | if (pidfd < 0) |
122 | ksft_exit_fail_msg( |
123 | msg: "%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 | msg: "%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 | msg: "%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(msg: "%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 | msg: "%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(msg: "%s test: Unsharing pid namespace not permitted\n" , |
169 | test_name); |
170 | return 0; |
171 | } |
172 | ksft_exit_fail_msg(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(msg: "%s test: Unsharing mount namespace not permitted\n" , |
180 | test_name); |
181 | return 0; |
182 | } |
183 | ksft_exit_fail_msg(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(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(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(msg: "pid to recycle is %d\n" , pid2); |
220 | pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); |
221 | } |
222 | |
223 | if (wait_for_pid(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(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(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(pid: pid1); |
325 | switch (ret) { |
326 | case PIDFD_FAIL: |
327 | ksft_exit_fail_msg( |
328 | msg: "%s test: Managed to signal recycled pid %d\n" , |
329 | test_name, PID_RECYCLE); |
330 | case PIDFD_PASS: |
331 | ksft_exit_fail_msg(msg: "%s test: Failed to recycle pid %d\n" , |
332 | test_name, PID_RECYCLE); |
333 | case PIDFD_SKIP: |
334 | ksft_test_result_skip(msg: "%s test: Skipping test\n" , test_name); |
335 | ret = 0; |
336 | break; |
337 | case PIDFD_XFAIL: |
338 | ksft_test_result_pass( |
339 | msg: "%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(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 | msg: "%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 | msg: "%s test: pidfd_send_signal() syscall not supported\n" , |
367 | test_name); |
368 | return 0; |
369 | } |
370 | ksft_exit_fail_msg(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 | msg: "%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(msg: "Child Thread: starting. pid %d tid %ld ; and sleeping\n" , |
385 | getpid(), syscall(SYS_gettid)); |
386 | ksft_print_msg(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(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(msg: "Parent: pid: %d\n" , getpid()); |
451 | pid = pidfd_clone(CLONE_PIDFD, pidfd: &pidfd, fn: 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(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(msg: "Parent: error\n" ); |
462 | |
463 | if (ret == pid) |
464 | ksft_print_msg(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(msg: "%s test: Failed\n" , test_name); |
477 | else |
478 | ksft_test_result_pass(msg: "%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(msg: "Parent: pid: %d\n" , getpid()); |
524 | pid = pidfd_clone(CLONE_PIDFD, pidfd: &pidfd, fn: 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(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(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(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(msg: "%s test: Failed\n" , test_name); |
557 | else |
558 | ksft_test_result_pass(msg: "%s test: Passed\n" , test_name); |
559 | } |
560 | |
561 | int main(int argc, char **argv) |
562 | { |
563 | ksft_print_header(); |
564 | ksft_set_plan(plan: 8); |
565 | |
566 | test_pidfd_poll_exec(use_waitpid: 0); |
567 | test_pidfd_poll_exec(use_waitpid: 1); |
568 | test_pidfd_poll_leader_exit(use_waitpid: 0); |
569 | test_pidfd_poll_leader_exit(use_waitpid: 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 | return ksft_exit_pass(); |
576 | } |
577 | |