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/procdesc.h> 31 #include <sys/resource.h> 32 #include <sys/time.h> 33 #include <sys/user.h> 34 #include <sys/wait.h> 35 36 #include <atf-c.h> 37 #include <signal.h> 38 #include <string.h> 39 40 /* basic usage */ 41 ATF_TC_WITHOUT_HEAD(basic); 42 ATF_TC_BODY(basic, tc) 43 { 44 int fdp = -1; 45 pid_t pid; 46 int r, status; 47 struct __wrusage ru; 48 siginfo_t si; 49 50 bzero(&ru, sizeof(ru)); 51 52 pid = pdfork(&fdp, 0); 53 if (pid == 0) 54 _exit(42); 55 ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno)); 56 ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor"); 57 58 r = pdwait(fdp, &status, WEXITED, &ru, &si); 59 ATF_CHECK_EQ(r, 0); 60 ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42); 61 ATF_CHECK(ru.wru_self.ru_stime.tv_usec > 0); 62 ATF_CHECK_EQ(si.si_signo, SIGCHLD); 63 ATF_CHECK_EQ(si.si_pid, pid); 64 ATF_CHECK_EQ(si.si_status, WEXITSTATUS(status)); 65 66 close(fdp); 67 } 68 69 /* pdwait should work in capability mode */ 70 ATF_TC_WITHOUT_HEAD(capsicum); 71 ATF_TC_BODY(capsicum, tc) 72 { 73 int fdp = -1; 74 pid_t pid; 75 int status, r; 76 77 pid = pdfork(&fdp, 0); 78 if (pid == 0) 79 _exit(42); 80 ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno)); 81 ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor"); 82 83 ATF_CHECK_EQ_MSG(0, cap_enter(), "cap_enter: %s", strerror(errno)); 84 r = pdwait(fdp, &status, WEXITED, NULL, NULL); 85 ATF_CHECK_EQ(r, 0); 86 ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42); 87 88 close(fdp); 89 } 90 91 /* pdwait should return EBADF if its argument is not a file descriptor */ 92 ATF_TC_WITHOUT_HEAD(ebadf); 93 ATF_TC_BODY(ebadf, tc) 94 { 95 ATF_REQUIRE_ERRNO(EBADF, pdwait(99999, NULL, WEXITED, NULL, NULL) < 0); 96 } 97 98 /* pdwait should return efault if the status argument is invalid. */ 99 ATF_TC_WITHOUT_HEAD(efault1); 100 ATF_TC_BODY(efault1, tc) 101 { 102 int fdp = -1; 103 pid_t pid; 104 105 pid = pdfork(&fdp, 0); 106 if (pid == 0) 107 _exit(42); 108 ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno)); 109 ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor"); 110 111 ATF_CHECK_ERRNO(EFAULT, pdwait(fdp, (int*)-1, WEXITED, NULL, NULL) < 0); 112 113 close(fdp); 114 } 115 116 /* pdwait should return efault2 if the usage argument is invalid. */ 117 ATF_TC_WITHOUT_HEAD(efault2); 118 ATF_TC_BODY(efault2, tc) 119 { 120 int fdp = -1; 121 pid_t pid; 122 123 pid = pdfork(&fdp, 0); 124 if (pid == 0) 125 _exit(42); 126 ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno)); 127 ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor"); 128 129 ATF_CHECK_ERRNO(EFAULT, 130 pdwait(fdp, NULL, WEXITED, (struct __wrusage*)-1, NULL) < 0); 131 132 close(fdp); 133 } 134 135 /* pdwait should return efault if the siginfo argument is invalid. */ 136 ATF_TC_WITHOUT_HEAD(efault3); 137 ATF_TC_BODY(efault3, tc) 138 { 139 int fdp = -1; 140 pid_t pid; 141 142 pid = pdfork(&fdp, 0); 143 if (pid == 0) 144 _exit(42); 145 ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno)); 146 ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor"); 147 148 ATF_CHECK_ERRNO(EFAULT, 149 pdwait(fdp, NULL, WEXITED, NULL, (struct __siginfo*)-1) < 0); 150 151 close(fdp); 152 } 153 154 /* pdwait should return einval if the arguments are bad */ 155 ATF_TC_WITHOUT_HEAD(einval); 156 ATF_TC_BODY(einval, tc) 157 { 158 int fdp = -1; 159 pid_t pid; 160 161 pid = pdfork(&fdp, 0); 162 if (pid == 0) 163 _exit(42); 164 ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno)); 165 ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor"); 166 167 ATF_CHECK_ERRNO(EINVAL, pdwait(fdp, NULL, 0, NULL, NULL) < 0); 168 ATF_CHECK_ERRNO(EINVAL, pdwait(fdp, NULL, -1, NULL, NULL) < 0); 169 ATF_CHECK_ERRNO(EINVAL, 170 pdwait(STDERR_FILENO, NULL, WEXITED, NULL, NULL) < 0); 171 172 close(fdp); 173 } 174 175 /* pdwait should fail without the cap_pdwait_rights bit */ 176 ATF_TC_WITHOUT_HEAD(enotcap); 177 ATF_TC_BODY(enotcap, tc) 178 { 179 cap_rights_t rights; 180 int fdp = -1; 181 pid_t pid; 182 int status; 183 184 /*cap_rights_init(&rights, CAP_RIGHTS_ALL);*/ 185 CAP_ALL(&rights); 186 cap_rights_clear(&rights, CAP_PDWAIT); 187 188 pid = pdfork(&fdp, 0); 189 if (pid == 0) 190 _exit(42); 191 ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno)); 192 ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor"); 193 194 ATF_CHECK_EQ_MSG(0, cap_enter(), "cap_enter: %s", strerror(errno)); 195 ATF_REQUIRE_EQ_MSG(0, cap_rights_limit(fdp, &rights), 196 "cap_rights_limit %s", strerror(errno)); 197 198 ATF_REQUIRE_ERRNO(ENOTCAPABLE, 199 pdwait(fdp, &status, WEXITED, NULL, NULL) < 0); 200 201 close(fdp); 202 } 203 204 /* 205 * Even though the process descriptor is still open, there is no more process 206 * to signal after pdwait() has returned. 207 */ 208 ATF_TC_WITHOUT_HEAD(pdkill_after_pdwait); 209 ATF_TC_BODY(pdkill_after_pdwait, tc) 210 { 211 int fdp = -1; 212 pid_t pid; 213 int r, status; 214 215 pid = pdfork(&fdp, 0); 216 if (pid == 0) 217 _exit(42); 218 ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno)); 219 ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor"); 220 221 r = pdwait(fdp, &status, WEXITED, NULL, NULL); 222 ATF_CHECK_EQ(r, 0); 223 ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42); 224 225 ATF_REQUIRE_ERRNO(ESRCH, pdkill(fdp, SIGTERM) < 0); 226 227 close(fdp); 228 } 229 230 /* 231 * Even though the process descriptor is still open, there is no more status to 232 * return after a pid-based wait() function has already returned it. 233 */ 234 ATF_TC_WITHOUT_HEAD(pdwait_after_waitpid); 235 ATF_TC_BODY(pdwait_after_waitpid, tc) 236 { 237 int fdp = -1; 238 pid_t pid, waited_pid; 239 int status; 240 241 pid = pdfork(&fdp, 0); 242 if (pid == 0) 243 _exit(42); 244 ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno)); 245 ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor"); 246 247 waited_pid = waitpid(pid, &status, WEXITED); 248 249 ATF_CHECK_EQ(pid, waited_pid); 250 ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42); 251 252 ATF_REQUIRE_ERRNO(ESRCH, pdwait(fdp, NULL, WEXITED, NULL, NULL) < 0); 253 254 close(fdp); 255 } 256 257 /* Called twice, waitpid should return ESRCH the second time */ 258 ATF_TC_WITHOUT_HEAD(twice); 259 ATF_TC_BODY(twice, tc) 260 { 261 int fdp = -1; 262 pid_t pid; 263 int r, status; 264 265 pid = pdfork(&fdp, 0); 266 if (pid == 0) 267 _exit(42); 268 ATF_REQUIRE_MSG(pid >= 0, "pdfork failed: %s", strerror(errno)); 269 ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor"); 270 271 r = pdwait(fdp, &status, WEXITED, NULL, NULL); 272 ATF_CHECK_EQ(r, 0); 273 ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42); 274 275 ATF_REQUIRE_ERRNO(ESRCH, pdwait(fdp, NULL, WEXITED, NULL, NULL) < 0); 276 277 close(fdp); 278 } 279 280 ATF_TP_ADD_TCS(tp) 281 { 282 ATF_TP_ADD_TC(tp, basic); 283 ATF_TP_ADD_TC(tp, capsicum); 284 ATF_TP_ADD_TC(tp, ebadf); 285 ATF_TP_ADD_TC(tp, enotcap); 286 ATF_TP_ADD_TC(tp, twice); 287 ATF_TP_ADD_TC(tp, efault1); 288 ATF_TP_ADD_TC(tp, efault2); 289 ATF_TP_ADD_TC(tp, efault3); 290 ATF_TP_ADD_TC(tp, einval); 291 ATF_TP_ADD_TC(tp, pdwait_after_waitpid); 292 ATF_TP_ADD_TC(tp, pdkill_after_pdwait); 293 294 return (atf_no_error()); 295 } 296