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