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