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