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; 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 pid_t pid; 51 siginfo_t info = { 52 .si_signo = 0, 53 }; 54 55 pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC); 56 ASSERT_GE(pidfd, 0); 57 58 pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 59 ASSERT_NE(pid, 0); 60 EXPECT_EQ(close(pidfd), 0); 61 pidfd = -1; 62 63 pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC); 64 ASSERT_GE(pidfd, 0); 65 66 pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 67 ASSERT_NE(pid, 0); 68 EXPECT_EQ(close(pidfd), 0); 69 pidfd = -1; 70 71 pid = sys_clone3(&args); 72 ASSERT_GE(pid, 0); 73 74 if (pid == 0) 75 exit(EXIT_SUCCESS); 76 77 pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 78 ASSERT_GE(pid, 0); 79 ASSERT_EQ(WIFEXITED(info.si_status), true); 80 ASSERT_EQ(WEXITSTATUS(info.si_status), 0); 81 EXPECT_EQ(close(pidfd), 0); 82 83 ASSERT_EQ(info.si_signo, SIGCHLD); 84 ASSERT_EQ(info.si_code, CLD_EXITED); 85 ASSERT_EQ(info.si_pid, parent_tid); 86 } 87 88 TEST(wait_states) 89 { 90 int pidfd = -1; 91 pid_t parent_tid = -1; 92 struct clone_args args = { 93 .parent_tid = ptr_to_u64(&parent_tid), 94 .pidfd = ptr_to_u64(&pidfd), 95 .flags = CLONE_PIDFD | CLONE_PARENT_SETTID, 96 .exit_signal = SIGCHLD, 97 }; 98 int pfd[2]; 99 pid_t pid; 100 siginfo_t info = { 101 .si_signo = 0, 102 }; 103 104 ASSERT_EQ(pipe(pfd), 0); 105 pid = sys_clone3(&args); 106 ASSERT_GE(pid, 0); 107 108 if (pid == 0) { 109 char buf[2]; 110 111 close(pfd[1]); 112 kill(getpid(), SIGSTOP); 113 ASSERT_EQ(read(pfd[0], buf, 1), 1); 114 close(pfd[0]); 115 kill(getpid(), SIGSTOP); 116 exit(EXIT_SUCCESS); 117 } 118 119 close(pfd[0]); 120 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0); 121 ASSERT_EQ(info.si_signo, SIGCHLD); 122 ASSERT_EQ(info.si_code, CLD_STOPPED); 123 ASSERT_EQ(info.si_pid, parent_tid); 124 125 ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0); 126 127 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL), 0); 128 ASSERT_EQ(write(pfd[1], "C", 1), 1); 129 close(pfd[1]); 130 ASSERT_EQ(info.si_signo, SIGCHLD); 131 ASSERT_EQ(info.si_code, CLD_CONTINUED); 132 ASSERT_EQ(info.si_pid, parent_tid); 133 134 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL), 0); 135 ASSERT_EQ(info.si_signo, SIGCHLD); 136 ASSERT_EQ(info.si_code, CLD_STOPPED); 137 ASSERT_EQ(info.si_pid, parent_tid); 138 139 ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0), 0); 140 141 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0); 142 ASSERT_EQ(info.si_signo, SIGCHLD); 143 ASSERT_EQ(info.si_code, CLD_KILLED); 144 ASSERT_EQ(info.si_pid, parent_tid); 145 146 EXPECT_EQ(close(pidfd), 0); 147 } 148 149 TEST(wait_nonblock) 150 { 151 int pidfd; 152 unsigned int flags = 0; 153 pid_t parent_tid = -1; 154 struct clone_args args = { 155 .parent_tid = ptr_to_u64(&parent_tid), 156 .flags = CLONE_PARENT_SETTID, 157 .exit_signal = SIGCHLD, 158 }; 159 int ret; 160 pid_t pid; 161 siginfo_t info = { 162 .si_signo = 0, 163 }; 164 165 /* 166 * Callers need to see ECHILD with non-blocking pidfds when no child 167 * processes exists. 168 */ 169 pidfd = sys_pidfd_open(getpid(), PIDFD_NONBLOCK); 170 EXPECT_GE(pidfd, 0) { 171 /* pidfd_open() doesn't support PIDFD_NONBLOCK. */ 172 ASSERT_EQ(errno, EINVAL); 173 SKIP(return, "Skipping PIDFD_NONBLOCK test"); 174 } 175 176 ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 177 ASSERT_LT(ret, 0); 178 ASSERT_EQ(errno, ECHILD); 179 EXPECT_EQ(close(pidfd), 0); 180 181 pid = sys_clone3(&args); 182 ASSERT_GE(pid, 0); 183 184 if (pid == 0) { 185 kill(getpid(), SIGSTOP); 186 exit(EXIT_SUCCESS); 187 } 188 189 pidfd = sys_pidfd_open(pid, PIDFD_NONBLOCK); 190 EXPECT_GE(pidfd, 0) { 191 /* pidfd_open() doesn't support PIDFD_NONBLOCK. */ 192 ASSERT_EQ(errno, EINVAL); 193 SKIP(return, "Skipping PIDFD_NONBLOCK test"); 194 } 195 196 flags = fcntl(pidfd, F_GETFL, 0); 197 ASSERT_GT(flags, 0); 198 ASSERT_GT((flags & O_NONBLOCK), 0); 199 200 /* 201 * Callers need to see EAGAIN/EWOULDBLOCK with non-blocking pidfd when 202 * child processes exist but none have exited. 203 */ 204 ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 205 ASSERT_LT(ret, 0); 206 ASSERT_EQ(errno, EAGAIN); 207 208 /* 209 * Callers need to continue seeing 0 with non-blocking pidfd and 210 * WNOHANG raised explicitly when child processes exist but none have 211 * exited. 212 */ 213 ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED | WNOHANG, NULL); 214 ASSERT_EQ(ret, 0); 215 216 ASSERT_EQ(fcntl(pidfd, F_SETFL, (flags & ~O_NONBLOCK)), 0); 217 218 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0); 219 ASSERT_EQ(info.si_signo, SIGCHLD); 220 ASSERT_EQ(info.si_code, CLD_STOPPED); 221 ASSERT_EQ(info.si_pid, parent_tid); 222 223 ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0); 224 225 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0); 226 ASSERT_EQ(info.si_signo, SIGCHLD); 227 ASSERT_EQ(info.si_code, CLD_EXITED); 228 ASSERT_EQ(info.si_pid, parent_tid); 229 230 EXPECT_EQ(close(pidfd), 0); 231 } 232 233 TEST_HARNESS_MAIN 234