xref: /src/tests/sys/kern/pdwait.c (revision 05492ff6f636108c4fac40c259defe9b2eac7833)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2026 ConnectWise
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/types.h>
29 #include <sys/capsicum.h>
30 #include <sys/mman.h>
31 #include <sys/procdesc.h>
32 #include <sys/resource.h>
33 #include <sys/time.h>
34 #include <sys/user.h>
35 #include <sys/wait.h>
36 
37 #include <atf-c.h>
38 #include <signal.h>
39 #include <string.h>
40 
41 static void*
unmapped(void)42 unmapped(void) {
43 	void *unmapped;
44 
45 	unmapped = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_GUARD, -1, 0);
46 	ATF_REQUIRE(unmapped != MAP_FAILED);
47 
48 	return(unmapped);
49 }
50 
51 /* basic usage */
52 ATF_TC_WITHOUT_HEAD(basic);
ATF_TC_BODY(basic,tc)53 ATF_TC_BODY(basic, tc)
54 {
55 	int fdp = -1;
56 	pid_t pid;
57 	int r, status;
58 	struct __wrusage ru;
59 	siginfo_t si;
60 
61 	bzero(&ru, sizeof(ru));
62 
63 	pid = pdfork(&fdp, 0);
64 	if (pid == 0)
65 		_exit(42);
66 	ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno));
67 	ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor");
68 
69 	r = pdwait(fdp, &status, WEXITED, &ru, &si);
70 	ATF_CHECK_EQ(r, 0);
71 	ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42);
72 	ATF_CHECK(ru.wru_self.ru_stime.tv_usec > 0);
73 	ATF_CHECK_EQ(si.si_signo, SIGCHLD);
74 	ATF_CHECK_EQ(si.si_pid, pid);
75 	ATF_CHECK_EQ(si.si_status, WEXITSTATUS(status));
76 
77 	close(fdp);
78 }
79 
80 /* pdwait should work in capability mode */
81 ATF_TC_WITHOUT_HEAD(capsicum);
ATF_TC_BODY(capsicum,tc)82 ATF_TC_BODY(capsicum, tc)
83 {
84 	int fdp = -1;
85 	pid_t pid;
86 	int status, r;
87 
88 	pid = pdfork(&fdp, 0);
89 	if (pid == 0)
90 		_exit(42);
91 	ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno));
92 	ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor");
93 
94 	ATF_CHECK_EQ_MSG(0, cap_enter(), "cap_enter: %s", strerror(errno));
95 	r = pdwait(fdp, &status, WEXITED, NULL, NULL);
96 	ATF_CHECK_EQ(r, 0);
97 	ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42);
98 
99 	close(fdp);
100 }
101 
102 /* pdwait should return EBADF if its argument is not a file descriptor */
103 ATF_TC_WITHOUT_HEAD(ebadf);
ATF_TC_BODY(ebadf,tc)104 ATF_TC_BODY(ebadf, tc)
105 {
106 	ATF_REQUIRE_ERRNO(EBADF, pdwait(99999, NULL, WEXITED, NULL, NULL) < 0);
107 }
108 
109 /* pdwait should return efault if the status argument is invalid.  */
110 ATF_TC_WITHOUT_HEAD(efault1);
ATF_TC_BODY(efault1,tc)111 ATF_TC_BODY(efault1, tc)
112 {
113 	int fdp = -1;
114 	pid_t pid;
115 
116 	pid = pdfork(&fdp, 0);
117 	if (pid == 0)
118 		_exit(42);
119 	ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno));
120 	ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor");
121 
122 	ATF_CHECK_ERRNO(EFAULT,
123 	    pdwait(fdp, (int*)unmapped(), WEXITED, NULL, NULL) < 0);
124 
125 	close(fdp);
126 }
127 
128 /* pdwait should return efault2 if the usage argument is invalid.  */
129 ATF_TC_WITHOUT_HEAD(efault2);
ATF_TC_BODY(efault2,tc)130 ATF_TC_BODY(efault2, tc)
131 {
132 	int fdp = -1;
133 	pid_t pid;
134 
135 	pid = pdfork(&fdp, 0);
136 	if (pid == 0)
137 		_exit(42);
138 	ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno));
139 	ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor");
140 
141 	ATF_CHECK_ERRNO(EFAULT,
142 	    pdwait(fdp, NULL, WEXITED, (struct __wrusage*)unmapped(), NULL) < 0
143 	);
144 
145 	close(fdp);
146 }
147 
148 /* pdwait should return efault if the siginfo argument is invalid.  */
149 ATF_TC_WITHOUT_HEAD(efault3);
ATF_TC_BODY(efault3,tc)150 ATF_TC_BODY(efault3, tc)
151 {
152 	int fdp = -1;
153 	pid_t pid;
154 
155 	pid = pdfork(&fdp, 0);
156 	if (pid == 0)
157 		_exit(42);
158 	ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno));
159 	ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor");
160 
161 	ATF_CHECK_ERRNO(EFAULT,
162 	    pdwait(fdp, NULL, WEXITED, NULL, (struct __siginfo*)unmapped()) < 0
163 	);
164 
165 	close(fdp);
166 }
167 
168 /* pdwait should return einval if the arguments are bad */
169 ATF_TC_WITHOUT_HEAD(einval);
ATF_TC_BODY(einval,tc)170 ATF_TC_BODY(einval, tc)
171 {
172 	int fdp = -1;
173 	pid_t pid;
174 
175 	pid = pdfork(&fdp, 0);
176 	if (pid == 0)
177 		_exit(42);
178 	ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno));
179 	ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor");
180 
181 	ATF_CHECK_ERRNO(EINVAL, pdwait(fdp, NULL, 0, NULL, NULL) < 0);
182 	ATF_CHECK_ERRNO(EINVAL, pdwait(fdp, NULL, -1, NULL, NULL) < 0);
183 	ATF_CHECK_ERRNO(EINVAL,
184 	    pdwait(STDERR_FILENO, NULL, WEXITED, NULL, NULL) < 0);
185 
186 	close(fdp);
187 }
188 
189 /* pdwait should fail without the cap_pdwait_rights bit */
190 ATF_TC_WITHOUT_HEAD(enotcap);
ATF_TC_BODY(enotcap,tc)191 ATF_TC_BODY(enotcap, tc)
192 {
193 	cap_rights_t rights;
194 	int fdp = -1;
195 	pid_t pid;
196 	int status;
197 
198 	/*cap_rights_init(&rights, CAP_RIGHTS_ALL);*/
199 	CAP_ALL(&rights);
200 	cap_rights_clear(&rights, CAP_PDWAIT);
201 
202 	pid = pdfork(&fdp, 0);
203 	if (pid == 0)
204 		_exit(42);
205 	ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno));
206 	ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor");
207 
208 	ATF_CHECK_EQ_MSG(0, cap_enter(), "cap_enter: %s", strerror(errno));
209 	ATF_REQUIRE_EQ_MSG(0, cap_rights_limit(fdp, &rights),
210 	    "cap_rights_limit %s", strerror(errno));
211 
212 	ATF_REQUIRE_ERRNO(ENOTCAPABLE,
213 	    pdwait(fdp, &status, WEXITED, NULL, NULL) < 0);
214 
215 	close(fdp);
216 }
217 
218 /*
219  * Even though the process descriptor is still open, there is no more process
220  * to signal after pdwait() has returned.
221  */
222 ATF_TC_WITHOUT_HEAD(pdkill_after_pdwait);
ATF_TC_BODY(pdkill_after_pdwait,tc)223 ATF_TC_BODY(pdkill_after_pdwait, tc)
224 {
225 	int fdp = -1;
226 	pid_t pid;
227 	int r, status;
228 
229 	pid = pdfork(&fdp, 0);
230 	if (pid == 0)
231 		_exit(42);
232 	ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno));
233 	ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor");
234 
235 	r = pdwait(fdp, &status, WEXITED, NULL, NULL);
236 	ATF_CHECK_EQ(r, 0);
237 	ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42);
238 
239 	ATF_REQUIRE_ERRNO(ESRCH, pdkill(fdp, SIGTERM) < 0);
240 
241 	close(fdp);
242 }
243 
244 /*
245  * Even though the process descriptor is still open, there is no more status to
246  * return after a pid-based wait() function has already returned it.
247  */
248 ATF_TC_WITHOUT_HEAD(pdwait_after_waitpid);
ATF_TC_BODY(pdwait_after_waitpid,tc)249 ATF_TC_BODY(pdwait_after_waitpid, tc)
250 {
251 	int fdp = -1;
252 	pid_t pid, waited_pid;
253 	int status;
254 
255 	pid = pdfork(&fdp, 0);
256 	if (pid == 0)
257 		_exit(42);
258 	ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno));
259 	ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor");
260 
261 	waited_pid = waitpid(pid, &status, WEXITED);
262 
263 	ATF_CHECK_EQ(pid, waited_pid);
264 	ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42);
265 
266 	ATF_REQUIRE_ERRNO(ESRCH, pdwait(fdp, NULL, WEXITED, NULL, NULL) < 0);
267 
268 	close(fdp);
269 }
270 
271 /* Called twice, waitpid should return ESRCH the second time */
272 ATF_TC_WITHOUT_HEAD(twice);
ATF_TC_BODY(twice,tc)273 ATF_TC_BODY(twice, tc)
274 {
275 	int fdp = -1;
276 	pid_t pid;
277 	int r, status;
278 
279 	pid = pdfork(&fdp, 0);
280 	if (pid == 0)
281 		_exit(42);
282 	ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno));
283 	ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor");
284 
285 	r = pdwait(fdp, &status, WEXITED, NULL, NULL);
286 	ATF_CHECK_EQ(r, 0);
287 	ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42);
288 
289 	ATF_REQUIRE_ERRNO(ESRCH, pdwait(fdp, NULL, WEXITED, NULL, NULL) < 0);
290 
291 	close(fdp);
292 }
293 
ATF_TP_ADD_TCS(tp)294 ATF_TP_ADD_TCS(tp)
295 {
296 	ATF_TP_ADD_TC(tp, basic);
297 	ATF_TP_ADD_TC(tp, capsicum);
298 	ATF_TP_ADD_TC(tp, ebadf);
299 	ATF_TP_ADD_TC(tp, enotcap);
300 	ATF_TP_ADD_TC(tp, twice);
301 	ATF_TP_ADD_TC(tp, efault1);
302 	ATF_TP_ADD_TC(tp, efault2);
303 	ATF_TP_ADD_TC(tp, efault3);
304 	ATF_TP_ADD_TC(tp, einval);
305 	ATF_TP_ADD_TC(tp, pdwait_after_waitpid);
306 	ATF_TP_ADD_TC(tp, pdkill_after_pdwait);
307 
308 	return (atf_no_error());
309 }
310