Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pidfd: add pidfd_wait tests

Add tests for pidfd_wait() and CLONE_WAIT_PID:
- test that waitid(P_PIDFD) fails on /proc/<pid>
- test that waitid(P_PIDFD) fails on /dev/null
- test that waitid(P_PIDFD) can wait on a pidfd
- test that waitid(P_PIDFD) can wait on a pidfd and return siginfo_t
- test that waitid(P_PIDFD) works with WEXITED
- test that waitid(P_PIDFD) works with WSTOPPED
- test that waitid(P_PIDFD) works with WUNTRACED
- test that waitid(P_PIDFD) works with WCONTINUED
- test that waitid(P_PIDFD) works with WNOWAIT
- test that waitid(P_PIDFD)works with WNOHANG

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Joel Fernandes (Google) <joel@joelfernandes.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: David Howells <dhowells@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Andy Lutomirsky <luto@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Aleksa Sarai <cyphar@cyphar.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Link: https://lore.kernel.org/r/20190727222229.6516-3-christian@brauner.io

+298 -15
+1
tools/testing/selftests/pidfd/.gitignore
··· 1 1 pidfd_open_test 2 2 pidfd_test 3 + pidfd_wait
+1 -1
tools/testing/selftests/pidfd/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 CFLAGS += -g -I../../../../usr/include/ -lpthread 3 3 4 - TEST_GEN_PROGS := pidfd_test pidfd_open_test 4 + TEST_GEN_PROGS := pidfd_test pidfd_open_test pidfd_wait 5 5 6 6 include ../lib.mk 7 7
+25
tools/testing/selftests/pidfd/pidfd.h
··· 16 16 17 17 #include "../kselftest.h" 18 18 19 + #ifndef P_PIDFD 20 + #define P_PIDFD 3 21 + #endif 22 + 23 + #ifndef CLONE_PIDFD 24 + #define CLONE_PIDFD 0x00001000 25 + #endif 26 + 27 + #ifndef __NR_pidfd_open 28 + #define __NR_pidfd_open -1 29 + #endif 30 + 31 + #ifndef __NR_pidfd_send_signal 32 + #define __NR_pidfd_send_signal -1 33 + #endif 34 + 35 + #ifndef __NR_clone3 36 + #define __NR_clone3 -1 37 + #endif 38 + 19 39 /* 20 40 * The kernel reserves 300 pids via RESERVED_PIDS in kernel/pid.c 21 41 * That means, when it wraps around any pid < 300 will be skipped. ··· 73 53 return WEXITSTATUS(status); 74 54 } 75 55 56 + static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, 57 + unsigned int flags) 58 + { 59 + return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); 60 + } 76 61 77 62 #endif /* __PIDFD_H */
-14
tools/testing/selftests/pidfd/pidfd_test.c
··· 21 21 #include "pidfd.h" 22 22 #include "../kselftest.h" 23 23 24 - #ifndef __NR_pidfd_send_signal 25 - #define __NR_pidfd_send_signal -1 26 - #endif 27 - 28 24 #define str(s) _str(s) 29 25 #define _str(s) #s 30 26 #define CHILD_THREAD_MIN_WAIT 3 /* seconds */ 31 27 32 28 #define MAX_EVENTS 5 33 - 34 - #ifndef CLONE_PIDFD 35 - #define CLONE_PIDFD 0x00001000 36 - #endif 37 29 38 30 static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *)) 39 31 { ··· 37 45 #else 38 46 return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd); 39 47 #endif 40 - } 41 - 42 - static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, 43 - unsigned int flags) 44 - { 45 - return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); 46 48 } 47 49 48 50 static int signal_received;
+271
tools/testing/selftests/pidfd/pidfd_wait.c
··· 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 + }