577 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2 3#define _GNU_SOURCE4#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) #s27#define CHILD_THREAD_MIN_WAIT 3 /* seconds */28 29#define MAX_EVENTS 530 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#else41 return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd);42#endif43}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 send55 * 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 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 of147 * times then we skip the test to not go into an infinite loop or block for a148 * long time.149 */150#define PIDFD_MAX_DEFAULT 0x8000151 152static 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 been232 * 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 have267 * 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. This279 * needs to fail since this is a different process than280 * 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 else288 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 be313 * 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 351static 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 382static 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 395static 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 426static 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 443static 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 else478 ksft_test_result_pass("%s test: Passed\n", test_name);479}480 481static 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 490static time_t *child_exit_secs;491static 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 only501 * 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 509static 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 in538 * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll539 * doesn't prematurely return even though there are active threads540 */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 else558 ksft_test_result_pass("%s test: Passed\n", test_name);559}560 561int 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