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