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.h" 21 22 #define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr))) 23 24 static pid_t sys_clone3(struct clone_args *args) 25 { 26 return syscall(__NR_clone3, args, sizeof(struct clone_args)); 27 } 28 29 static int sys_waitid(int which, pid_t pid, siginfo_t *info, int options, 30 struct rusage *ru) 31 { 32 return syscall(__NR_waitid, which, pid, info, options, ru); 33 } 34 35 static int test_pidfd_wait_simple(void) 36 { 37 const char *test_name = "pidfd wait simple"; 38 int pidfd = -1, status = 0; 39 pid_t parent_tid = -1; 40 struct clone_args args = { 41 .parent_tid = ptr_to_u64(&parent_tid), 42 .pidfd = ptr_to_u64(&pidfd), 43 .flags = CLONE_PIDFD | CLONE_PARENT_SETTID, 44 .exit_signal = SIGCHLD, 45 }; 46 int ret; 47 pid_t pid; 48 siginfo_t info = { 49 .si_signo = 0, 50 }; 51 52 pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC); 53 if (pidfd < 0) 54 ksft_exit_fail_msg("%s test: failed to open /proc/self %s\n", 55 test_name, strerror(errno)); 56 57 pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 58 if (pid == 0) 59 ksft_exit_fail_msg( 60 "%s test: succeeded to wait on invalid pidfd %s\n", 61 test_name, strerror(errno)); 62 close(pidfd); 63 pidfd = -1; 64 65 pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC); 66 if (pidfd == 0) 67 ksft_exit_fail_msg("%s test: failed to open /dev/null %s\n", 68 test_name, strerror(errno)); 69 70 pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 71 if (pid == 0) 72 ksft_exit_fail_msg( 73 "%s test: succeeded to wait on invalid pidfd %s\n", 74 test_name, strerror(errno)); 75 close(pidfd); 76 pidfd = -1; 77 78 pid = sys_clone3(&args); 79 if (pid < 0) 80 ksft_exit_fail_msg("%s test: failed to create new process %s\n", 81 test_name, strerror(errno)); 82 83 if (pid == 0) 84 exit(EXIT_SUCCESS); 85 86 pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 87 if (pid < 0) 88 ksft_exit_fail_msg( 89 "%s test: failed to wait on process with pid %d and pidfd %d: %s\n", 90 test_name, parent_tid, pidfd, strerror(errno)); 91 92 if (!WIFEXITED(info.si_status) || WEXITSTATUS(info.si_status)) 93 ksft_exit_fail_msg( 94 "%s test: unexpected status received after waiting on process with pid %d and pidfd %d: %s\n", 95 test_name, parent_tid, pidfd, strerror(errno)); 96 close(pidfd); 97 98 if (info.si_signo != SIGCHLD) 99 ksft_exit_fail_msg( 100 "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n", 101 test_name, info.si_signo, parent_tid, pidfd, 102 strerror(errno)); 103 104 if (info.si_code != CLD_EXITED) 105 ksft_exit_fail_msg( 106 "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n", 107 test_name, info.si_code, parent_tid, pidfd, 108 strerror(errno)); 109 110 if (info.si_pid != parent_tid) 111 ksft_exit_fail_msg( 112 "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n", 113 test_name, info.si_pid, parent_tid, pidfd, 114 strerror(errno)); 115 116 ksft_test_result_pass("%s test: Passed\n", test_name); 117 return 0; 118 } 119 120 static int test_pidfd_wait_states(void) 121 { 122 const char *test_name = "pidfd wait states"; 123 int pidfd = -1, status = 0; 124 pid_t parent_tid = -1; 125 struct clone_args args = { 126 .parent_tid = ptr_to_u64(&parent_tid), 127 .pidfd = ptr_to_u64(&pidfd), 128 .flags = CLONE_PIDFD | CLONE_PARENT_SETTID, 129 .exit_signal = SIGCHLD, 130 }; 131 int ret; 132 pid_t pid; 133 siginfo_t info = { 134 .si_signo = 0, 135 }; 136 137 pid = sys_clone3(&args); 138 if (pid < 0) 139 ksft_exit_fail_msg("%s test: failed to create new process %s\n", 140 test_name, strerror(errno)); 141 142 if (pid == 0) { 143 kill(getpid(), SIGSTOP); 144 kill(getpid(), SIGSTOP); 145 exit(EXIT_SUCCESS); 146 } 147 148 ret = sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL); 149 if (ret < 0) 150 ksft_exit_fail_msg( 151 "%s test: failed to wait on WSTOPPED process with pid %d and pidfd %d: %s\n", 152 test_name, parent_tid, pidfd, strerror(errno)); 153 154 if (info.si_signo != SIGCHLD) 155 ksft_exit_fail_msg( 156 "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n", 157 test_name, info.si_signo, parent_tid, pidfd, 158 strerror(errno)); 159 160 if (info.si_code != CLD_STOPPED) 161 ksft_exit_fail_msg( 162 "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n", 163 test_name, info.si_code, parent_tid, pidfd, 164 strerror(errno)); 165 166 if (info.si_pid != parent_tid) 167 ksft_exit_fail_msg( 168 "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n", 169 test_name, info.si_pid, parent_tid, pidfd, 170 strerror(errno)); 171 172 ret = sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0); 173 if (ret < 0) 174 ksft_exit_fail_msg( 175 "%s test: failed to send signal to process with pid %d and pidfd %d: %s\n", 176 test_name, parent_tid, pidfd, strerror(errno)); 177 178 ret = sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL); 179 if (ret < 0) 180 ksft_exit_fail_msg( 181 "%s test: failed to wait WCONTINUED on process with pid %d and pidfd %d: %s\n", 182 test_name, parent_tid, pidfd, strerror(errno)); 183 184 if (info.si_signo != SIGCHLD) 185 ksft_exit_fail_msg( 186 "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n", 187 test_name, info.si_signo, parent_tid, pidfd, 188 strerror(errno)); 189 190 if (info.si_code != CLD_CONTINUED) 191 ksft_exit_fail_msg( 192 "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n", 193 test_name, info.si_code, parent_tid, pidfd, 194 strerror(errno)); 195 196 if (info.si_pid != parent_tid) 197 ksft_exit_fail_msg( 198 "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n", 199 test_name, info.si_pid, parent_tid, pidfd, 200 strerror(errno)); 201 202 ret = sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL); 203 if (ret < 0) 204 ksft_exit_fail_msg( 205 "%s test: failed to wait on WUNTRACED process with pid %d and pidfd %d: %s\n", 206 test_name, parent_tid, pidfd, strerror(errno)); 207 208 if (info.si_signo != SIGCHLD) 209 ksft_exit_fail_msg( 210 "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n", 211 test_name, info.si_signo, parent_tid, pidfd, 212 strerror(errno)); 213 214 if (info.si_code != CLD_STOPPED) 215 ksft_exit_fail_msg( 216 "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n", 217 test_name, info.si_code, parent_tid, pidfd, 218 strerror(errno)); 219 220 if (info.si_pid != parent_tid) 221 ksft_exit_fail_msg( 222 "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n", 223 test_name, info.si_pid, parent_tid, pidfd, 224 strerror(errno)); 225 226 ret = sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0); 227 if (ret < 0) 228 ksft_exit_fail_msg( 229 "%s test: failed to send SIGKILL to process with pid %d and pidfd %d: %s\n", 230 test_name, parent_tid, pidfd, strerror(errno)); 231 232 ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); 233 if (ret < 0) 234 ksft_exit_fail_msg( 235 "%s test: failed to wait on WEXITED process with pid %d and pidfd %d: %s\n", 236 test_name, parent_tid, pidfd, strerror(errno)); 237 238 if (info.si_signo != SIGCHLD) 239 ksft_exit_fail_msg( 240 "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n", 241 test_name, info.si_signo, parent_tid, pidfd, 242 strerror(errno)); 243 244 if (info.si_code != CLD_KILLED) 245 ksft_exit_fail_msg( 246 "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n", 247 test_name, info.si_code, parent_tid, pidfd, 248 strerror(errno)); 249 250 if (info.si_pid != parent_tid) 251 ksft_exit_fail_msg( 252 "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n", 253 test_name, info.si_pid, parent_tid, pidfd, 254 strerror(errno)); 255 256 close(pidfd); 257 258 ksft_test_result_pass("%s test: Passed\n", test_name); 259 return 0; 260 } 261 262 int main(int argc, char **argv) 263 { 264 ksft_print_header(); 265 ksft_set_plan(2); 266 267 test_pidfd_wait_simple(); 268 test_pidfd_wait_states(); 269 270 return ksft_exit_pass(); 271 } 272