1 /* SPDX-License-Identifier: GPL-2.0 */ 2 3 #define _GNU_SOURCE 4 #include <errno.h> 5 #include <linux/sched.h> 6 #include <linux/types.h> 7 #include <signal.h> 8 #include <stdint.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <sched.h> 12 #include <string.h> 13 #include <sys/resource.h> 14 #include <sys/time.h> 15 #include <sys/types.h> 16 #include <sys/wait.h> 17 #include <unistd.h> 18 19 #include "pidfd.h" 20 #include "../kselftest_harness.h" 21 22 #define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr))) 23 24 /* Attempt to de-conflict with the selftests tree. */ 25 #ifndef SKIP 26 #define SKIP(s, ...) XFAIL(s, ##__VA_ARGS__) 27 #endif 28 29 static pid_t sys_clone3(struct clone_args *args) 30 { 31 return syscall(__NR_clone3, args, sizeof(struct clone_args)); 32 } 33 34 static int sys_waitid(int which, pid_t pid, siginfo_t *info, int options, 35 struct rusage *ru) 36 { 37 return syscall(__NR_waitid, which, pid, info, options, ru); 38 } 39 40 TEST(wait_simple) 41 { 42 int pidfd = -1, status = 0; 43 pid_t parent_tid = -1; 44 struct clone_args args = { 45 .parent_tid = ptr_to_u64(&parent_tid), 46 .pidfd = ptr_to_u64(&pidfd), 47 .flags = CLONE_PIDFD | CLONE_PARENT_SETTID, 48 .exit_signal = SIGCHLD, 49 }; 50 int ret; 51 pid_t pid; 52 siginfo_t info = { 53 .si_signo = 0, 54 }; 55 56 pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC); 57 ASSERT_GE(pidfd, 0); 58 59 pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 60 ASSERT_NE(pid, 0); 61 EXPECT_EQ(close(pidfd), 0); 62 pidfd = -1; 63 64 pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC); 65 ASSERT_GE(pidfd, 0); 66 67 pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 68 ASSERT_NE(pid, 0); 69 EXPECT_EQ(close(pidfd), 0); 70 pidfd = -1; 71 72 pid = sys_clone3(&args); 73 ASSERT_GE(pid, 0); 74 75 if (pid == 0) 76 exit(EXIT_SUCCESS); 77 78 pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 79 ASSERT_GE(pid, 0); 80 ASSERT_EQ(WIFEXITED(info.si_status), true); 81 ASSERT_EQ(WEXITSTATUS(info.si_status), 0); 82 EXPECT_EQ(close(pidfd), 0); 83 84 ASSERT_EQ(info.si_signo, SIGCHLD); 85 ASSERT_EQ(info.si_code, CLD_EXITED); 86 ASSERT_EQ(info.si_pid, parent_tid); 87 } 88 89 TEST(wait_states) 90 { 91 int pidfd = -1, status = 0; 92 pid_t parent_tid = -1; 93 struct clone_args args = { 94 .parent_tid = ptr_to_u64(&parent_tid), 95 .pidfd = ptr_to_u64(&pidfd), 96 .flags = CLONE_PIDFD | CLONE_PARENT_SETTID, 97 .exit_signal = SIGCHLD, 98 }; 99 int ret; 100 pid_t pid; 101 siginfo_t info = { 102 .si_signo = 0, 103 }; 104 105 pid = sys_clone3(&args); 106 ASSERT_GE(pid, 0); 107 108 if (pid == 0) { 109 kill(getpid(), SIGSTOP); 110 kill(getpid(), SIGSTOP); 111 exit(EXIT_SUCCESS); 112 } 113 114 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0); 115 ASSERT_EQ(info.si_signo, SIGCHLD); 116 ASSERT_EQ(info.si_code, CLD_STOPPED); 117 ASSERT_EQ(info.si_pid, parent_tid); 118 119 ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0); 120 121 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL), 0); 122 ASSERT_EQ(info.si_signo, SIGCHLD); 123 ASSERT_EQ(info.si_code, CLD_CONTINUED); 124 ASSERT_EQ(info.si_pid, parent_tid); 125 126 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL), 0); 127 ASSERT_EQ(info.si_signo, SIGCHLD); 128 ASSERT_EQ(info.si_code, CLD_STOPPED); 129 ASSERT_EQ(info.si_pid, parent_tid); 130 131 ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0), 0); 132 133 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0); 134 ASSERT_EQ(info.si_signo, SIGCHLD); 135 ASSERT_EQ(info.si_code, CLD_KILLED); 136 ASSERT_EQ(info.si_pid, parent_tid); 137 138 EXPECT_EQ(close(pidfd), 0); 139 } 140 141 TEST(wait_nonblock) 142 { 143 int pidfd, status = 0; 144 unsigned int flags = 0; 145 pid_t parent_tid = -1; 146 struct clone_args args = { 147 .parent_tid = ptr_to_u64(&parent_tid), 148 .flags = CLONE_PARENT_SETTID, 149 .exit_signal = SIGCHLD, 150 }; 151 int ret; 152 pid_t pid; 153 siginfo_t info = { 154 .si_signo = 0, 155 }; 156 157 /* 158 * Callers need to see ECHILD with non-blocking pidfds when no child 159 * processes exists. 160 */ 161 pidfd = sys_pidfd_open(getpid(), PIDFD_NONBLOCK); 162 EXPECT_GE(pidfd, 0) { 163 /* pidfd_open() doesn't support PIDFD_NONBLOCK. */ 164 ASSERT_EQ(errno, EINVAL); 165 SKIP(return, "Skipping PIDFD_NONBLOCK test"); 166 } 167 168 ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 169 ASSERT_LT(ret, 0); 170 ASSERT_EQ(errno, ECHILD); 171 EXPECT_EQ(close(pidfd), 0); 172 173 pid = sys_clone3(&args); 174 ASSERT_GE(pid, 0); 175 176 if (pid == 0) { 177 kill(getpid(), SIGSTOP); 178 exit(EXIT_SUCCESS); 179 } 180 181 pidfd = sys_pidfd_open(pid, PIDFD_NONBLOCK); 182 EXPECT_GE(pidfd, 0) { 183 /* pidfd_open() doesn't support PIDFD_NONBLOCK. */ 184 ASSERT_EQ(errno, EINVAL); 185 SKIP(return, "Skipping PIDFD_NONBLOCK test"); 186 } 187 188 flags = fcntl(pidfd, F_GETFL, 0); 189 ASSERT_GT(flags, 0); 190 ASSERT_GT((flags & O_NONBLOCK), 0); 191 192 /* 193 * Callers need to see EAGAIN/EWOULDBLOCK with non-blocking pidfd when 194 * child processes exist but none have exited. 195 */ 196 ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 197 ASSERT_LT(ret, 0); 198 ASSERT_EQ(errno, EAGAIN); 199 200 /* 201 * Callers need to continue seeing 0 with non-blocking pidfd and 202 * WNOHANG raised explicitly when child processes exist but none have 203 * exited. 204 */ 205 ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED | WNOHANG, NULL); 206 ASSERT_EQ(ret, 0); 207 208 ASSERT_EQ(fcntl(pidfd, F_SETFL, (flags & ~O_NONBLOCK)), 0); 209 210 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0); 211 ASSERT_EQ(info.si_signo, SIGCHLD); 212 ASSERT_EQ(info.si_code, CLD_STOPPED); 213 ASSERT_EQ(info.si_pid, parent_tid); 214 215 ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0); 216 217 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0); 218 ASSERT_EQ(info.si_signo, SIGCHLD); 219 ASSERT_EQ(info.si_code, CLD_EXITED); 220 ASSERT_EQ(info.si_pid, parent_tid); 221 222 EXPECT_EQ(close(pidfd), 0); 223 } 224 225 TEST_HARNESS_MAIN 226