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
sys_clone3(struct clone_args * args)29 static pid_t sys_clone3(struct clone_args *args)
30 {
31 return syscall(__NR_clone3, args, sizeof(struct clone_args));
32 }
33
sys_waitid(int which,pid_t pid,siginfo_t * info,int options,struct rusage * ru)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
TEST(wait_simple)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
TEST(wait_states)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 pid_t pid;
99 siginfo_t info = {
100 .si_signo = 0,
101 };
102
103 pid = sys_clone3(&args);
104 ASSERT_GE(pid, 0);
105
106 if (pid == 0) {
107 kill(getpid(), SIGSTOP);
108 kill(getpid(), SIGSTOP);
109 exit(EXIT_SUCCESS);
110 }
111
112 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
113 ASSERT_EQ(info.si_signo, SIGCHLD);
114 ASSERT_EQ(info.si_code, CLD_STOPPED);
115 ASSERT_EQ(info.si_pid, parent_tid);
116
117 ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
118
119 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL), 0);
120 ASSERT_EQ(info.si_signo, SIGCHLD);
121 ASSERT_EQ(info.si_code, CLD_CONTINUED);
122 ASSERT_EQ(info.si_pid, parent_tid);
123
124 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL), 0);
125 ASSERT_EQ(info.si_signo, SIGCHLD);
126 ASSERT_EQ(info.si_code, CLD_STOPPED);
127 ASSERT_EQ(info.si_pid, parent_tid);
128
129 ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0), 0);
130
131 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
132 ASSERT_EQ(info.si_signo, SIGCHLD);
133 ASSERT_EQ(info.si_code, CLD_KILLED);
134 ASSERT_EQ(info.si_pid, parent_tid);
135
136 EXPECT_EQ(close(pidfd), 0);
137 }
138
TEST(wait_nonblock)139 TEST(wait_nonblock)
140 {
141 int pidfd, status = 0;
142 unsigned int flags = 0;
143 pid_t parent_tid = -1;
144 struct clone_args args = {
145 .parent_tid = ptr_to_u64(&parent_tid),
146 .flags = CLONE_PARENT_SETTID,
147 .exit_signal = SIGCHLD,
148 };
149 int ret;
150 pid_t pid;
151 siginfo_t info = {
152 .si_signo = 0,
153 };
154
155 /*
156 * Callers need to see ECHILD with non-blocking pidfds when no child
157 * processes exists.
158 */
159 pidfd = sys_pidfd_open(getpid(), PIDFD_NONBLOCK);
160 EXPECT_GE(pidfd, 0) {
161 /* pidfd_open() doesn't support PIDFD_NONBLOCK. */
162 ASSERT_EQ(errno, EINVAL);
163 SKIP(return, "Skipping PIDFD_NONBLOCK test");
164 }
165
166 ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
167 ASSERT_LT(ret, 0);
168 ASSERT_EQ(errno, ECHILD);
169 EXPECT_EQ(close(pidfd), 0);
170
171 pid = sys_clone3(&args);
172 ASSERT_GE(pid, 0);
173
174 if (pid == 0) {
175 kill(getpid(), SIGSTOP);
176 exit(EXIT_SUCCESS);
177 }
178
179 pidfd = sys_pidfd_open(pid, PIDFD_NONBLOCK);
180 EXPECT_GE(pidfd, 0) {
181 /* pidfd_open() doesn't support PIDFD_NONBLOCK. */
182 ASSERT_EQ(errno, EINVAL);
183 SKIP(return, "Skipping PIDFD_NONBLOCK test");
184 }
185
186 flags = fcntl(pidfd, F_GETFL, 0);
187 ASSERT_GT(flags, 0);
188 ASSERT_GT((flags & O_NONBLOCK), 0);
189
190 /*
191 * Callers need to see EAGAIN/EWOULDBLOCK with non-blocking pidfd when
192 * child processes exist but none have exited.
193 */
194 ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
195 ASSERT_LT(ret, 0);
196 ASSERT_EQ(errno, EAGAIN);
197
198 /*
199 * Callers need to continue seeing 0 with non-blocking pidfd and
200 * WNOHANG raised explicitly when child processes exist but none have
201 * exited.
202 */
203 ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED | WNOHANG, NULL);
204 ASSERT_EQ(ret, 0);
205
206 ASSERT_EQ(fcntl(pidfd, F_SETFL, (flags & ~O_NONBLOCK)), 0);
207
208 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
209 ASSERT_EQ(info.si_signo, SIGCHLD);
210 ASSERT_EQ(info.si_code, CLD_STOPPED);
211 ASSERT_EQ(info.si_pid, parent_tid);
212
213 ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
214
215 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
216 ASSERT_EQ(info.si_signo, SIGCHLD);
217 ASSERT_EQ(info.si_code, CLD_EXITED);
218 ASSERT_EQ(info.si_pid, parent_tid);
219
220 EXPECT_EQ(close(pidfd), 0);
221 }
222
223 TEST_HARNESS_MAIN
224