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* 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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 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