xref: /openbsd/regress/lib/libc/sys/t_kill.c (revision 73471bf0)
1 /*	$OpenBSD: t_kill.c,v 1.4 2021/12/13 16:56:48 deraadt Exp $	*/
2 /* $NetBSD: t_kill.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $ */
3 
4 /*-
5  * Copyright (c) 2011 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Jukka Ruohonen.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "macros.h"
34 
35 #include <sys/wait.h>
36 
37 #include <errno.h>
38 #include <limits.h>
39 #include <pwd.h>
40 #include <signal.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 
44 #include "atf-c.h"
45 
46 ATF_TC(kill_basic);
47 ATF_TC_HEAD(kill_basic, tc)
48 {
49 	atf_tc_set_md_var(tc, "descr", "Test that kill(2) works");
50 }
51 
52 ATF_TC_BODY(kill_basic, tc)
53 {
54 	const int sig[] = { SIGHUP, SIGINT, SIGKILL, SIGTERM };
55 	pid_t pid;
56 	size_t i;
57 	int sta;
58 
59 	for (i = 0; i < __arraycount(sig); i++) {
60 
61 		pid = fork();
62 		ATF_REQUIRE(pid >= 0);
63 
64 		switch (pid) {
65 
66 		case 0:
67 			pause();
68 			break;
69 
70 		default:
71 			ATF_REQUIRE(kill(pid, sig[i]) == 0);
72 		}
73 
74 		(void)wait(&sta);
75 
76 		if (WIFSIGNALED(sta) == 0 || WTERMSIG(sta) != sig[i])
77 			atf_tc_fail("kill(2) failed to kill child");
78 	}
79 }
80 
81 ATF_TC(kill_err);
82 ATF_TC_HEAD(kill_err, tc)
83 {
84 	atf_tc_set_md_var(tc, "descr", "Test error conditions of kill(2)");
85 }
86 
87 ATF_TC_BODY(kill_err, tc)
88 {
89 	int rv, sta;
90 	pid_t pid;
91 
92 	pid = fork();
93 	ATF_REQUIRE(pid >= 0);
94 
95 	if (pid == 0) {
96 
97 		errno = 0;
98 		rv = kill(getpid(), -1);
99 
100 		if (rv == 0 || errno != EINVAL)
101 			_exit(EINVAL);
102 
103 		errno = 0;
104 		rv = kill(INT_MAX, SIGUSR1);
105 
106 		if (rv == 0 || errno != ESRCH)
107 			_exit(ESRCH);
108 
109 		_exit(EXIT_SUCCESS);
110 	}
111 
112 	(void)wait(&sta);
113 
114 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) {
115 
116 		if (WEXITSTATUS(sta) == EINVAL)
117 			atf_tc_fail("expected EINVAL, but kill(2) succeeded");
118 
119 		if (WEXITSTATUS(sta) == ESRCH)
120 			atf_tc_fail("expected ESRCH, but kill(2) succeeded");
121 
122 		atf_tc_fail("unknown error from kill(2)");
123 	}
124 }
125 
126 ATF_TC(kill_perm);
127 ATF_TC_HEAD(kill_perm, tc)
128 {
129 	atf_tc_set_md_var(tc, "descr", "Test kill(2) permissions");
130 	atf_tc_set_md_var(tc, "require.user", "root");
131 }
132 
133 ATF_TC_BODY(kill_perm, tc)
134 {
135 	struct passwd *pw;
136 	pid_t cpid, ppid;
137 	uid_t cuid = 0;
138 	uid_t puid = 0;
139 	int sta;
140 
141 	/*
142 	 * Test that kill(2) fails when called
143 	 * for a PID owned by another user.
144 	 */
145 	pw = getpwnam("operator");
146 
147 	if (pw != NULL)
148 		cuid = pw->pw_uid;
149 
150 	pw = getpwnam("nobody");
151 
152 	if (pw != NULL)
153 		puid = pw->pw_uid;
154 
155 	if (cuid == 0 || puid == 0 || cuid == puid)
156 		atf_tc_fail("getpwnam(3) failed");
157 
158 	ppid = fork();
159 
160 	if (ppid < 0)
161 		_exit(EXIT_FAILURE);
162 
163 	if (ppid == 0) {
164 
165 		cpid = fork();
166 
167 		if (cpid < 0)
168 			_exit(EXIT_FAILURE);
169 
170 		if (cpid == 0) {
171 
172 			if (setuid(cuid) < 0)
173 				_exit(EXIT_FAILURE);
174 			else {
175 				(void)sleep(1);
176 			}
177 
178 			_exit(EXIT_SUCCESS);
179 		}
180 
181 		/*
182 		 * Try to kill the child after having
183 		 * set the real and effective UID.
184 		 */
185 		if (setuid(puid) != 0)
186 			_exit(EXIT_FAILURE);
187 
188 		errno = 0;
189 
190 		if (kill(cpid, SIGKILL) == 0)
191 			_exit(EPERM);
192 
193 		if (errno != EPERM)
194 			_exit(EPERM);
195 
196 		(void)waitpid(cpid, &sta, 0);
197 
198 		_exit(EXIT_SUCCESS);
199 	}
200 
201 	(void)waitpid(ppid, &sta, 0);
202 
203 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) == EPERM)
204 		atf_tc_fail("killed a process of another user");
205 
206 	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
207 		atf_tc_fail("unknown error from kill(2)");
208 }
209 
210 ATF_TC(kill_pgrp_neg);
211 ATF_TC_HEAD(kill_pgrp_neg, tc)
212 {
213 	atf_tc_set_md_var(tc, "descr", "Test kill(2) with process group, #2");
214 }
215 
216 ATF_TC_BODY(kill_pgrp_neg, tc)
217 {
218 	const int maxiter = 3;
219 	pid_t cpid, ppid;
220 	int i, sta;
221 
222 	ppid = fork();
223 	ATF_REQUIRE(ppid >= 0);
224 
225 	if (ppid == 0) {
226 
227 		ATF_REQUIRE(setpgid(0, 0) == 0);
228 
229 		for (i = 0; i < maxiter; i++) {
230 
231 			cpid = fork();
232 			ATF_REQUIRE(cpid >= 0);
233 
234 			if (cpid == 0)
235 				pause();
236 		}
237 
238 		/*
239 		 * Test the variant of killpg(3); if the process number
240 		 * is negative but not -1, the signal should be sent to
241 		 * all processes whose process group ID is equal to the
242 		 * absolute value of the process number.
243 		 */
244 		ATF_REQUIRE(kill(-getpgrp(), SIGKILL) == 0);
245 
246 		(void)sleep(1);
247 
248 		_exit(EXIT_SUCCESS);
249 	}
250 
251 	(void)waitpid(ppid, &sta, 0);
252 
253 	if (WIFSIGNALED(sta) == 0 || WTERMSIG(sta) != SIGKILL)
254 		atf_tc_fail("failed to kill(2) a process group");
255 }
256 
257 ATF_TC(kill_pgrp_zero);
258 ATF_TC_HEAD(kill_pgrp_zero, tc)
259 {
260 	atf_tc_set_md_var(tc, "descr", "Test kill(2) with process group, #1");
261 }
262 
263 ATF_TC_BODY(kill_pgrp_zero, tc)
264 {
265 	const int maxiter = 3;
266 	pid_t cpid, ppid;
267 	int i, sta;
268 
269 	ppid = fork();
270 	ATF_REQUIRE(ppid >= 0);
271 
272 	if (ppid == 0) {
273 
274 		ATF_REQUIRE(setpgid(0, 0) == 0);
275 
276 		for (i = 0; i < maxiter; i++) {
277 
278 			cpid = fork();
279 			ATF_REQUIRE(cpid >= 0);
280 
281 			if (cpid == 0)
282 				pause();
283 		}
284 
285 		/*
286 		 * If the supplied process number is zero,
287 		 * the signal should be sent to all processes
288 		 * under the current process group.
289 		 */
290 		ATF_REQUIRE(kill(0, SIGKILL) == 0);
291 
292 		(void)sleep(1);
293 
294 		_exit(EXIT_SUCCESS);
295 	}
296 
297 	(void)waitpid(ppid, &sta, 0);
298 
299 	if (WIFSIGNALED(sta) == 0 || WTERMSIG(sta) != SIGKILL)
300 		atf_tc_fail("failed to kill(2) a process group");
301 }
302 
303 ATF_TP_ADD_TCS(tp)
304 {
305 
306 	ATF_TP_ADD_TC(tp, kill_basic);
307 	ATF_TP_ADD_TC(tp, kill_err);
308 	ATF_TP_ADD_TC(tp, kill_perm);
309 	ATF_TP_ADD_TC(tp, kill_pgrp_neg);
310 	ATF_TP_ADD_TC(tp, kill_pgrp_zero);
311 
312 	return atf_no_error();
313 }
314