1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "namespace.h" 33 #include <sys/queue.h> 34 #include <sys/wait.h> 35 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <sched.h> 39 #include <spawn.h> 40 #include <signal.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 #include "un-namespace.h" 45 #include "libc_private.h" 46 47 extern char **environ; 48 49 struct __posix_spawnattr { 50 short sa_flags; 51 pid_t sa_pgroup; 52 struct sched_param sa_schedparam; 53 int sa_schedpolicy; 54 sigset_t sa_sigdefault; 55 sigset_t sa_sigmask; 56 }; 57 58 struct __posix_spawn_file_actions { 59 STAILQ_HEAD(, __posix_spawn_file_actions_entry) fa_list; 60 }; 61 62 typedef struct __posix_spawn_file_actions_entry { 63 STAILQ_ENTRY(__posix_spawn_file_actions_entry) fae_list; 64 enum { FAE_OPEN, FAE_DUP2, FAE_CLOSE } fae_action; 65 66 int fae_fildes; 67 union { 68 struct { 69 char *path; 70 #define fae_path fae_data.open.path 71 int oflag; 72 #define fae_oflag fae_data.open.oflag 73 mode_t mode; 74 #define fae_mode fae_data.open.mode 75 } open; 76 struct { 77 int newfildes; 78 #define fae_newfildes fae_data.dup2.newfildes 79 } dup2; 80 } fae_data; 81 } posix_spawn_file_actions_entry_t; 82 83 /* 84 * Spawn routines 85 */ 86 87 static int 88 process_spawnattr(const posix_spawnattr_t sa) 89 { 90 struct sigaction sigact = { .sa_flags = 0, .sa_handler = SIG_DFL }; 91 int i; 92 93 /* 94 * POSIX doesn't really describe in which order everything 95 * should be set. We'll just set them in the order in which they 96 * are mentioned. 97 */ 98 99 /* Set process group */ 100 if (sa->sa_flags & POSIX_SPAWN_SETPGROUP) { 101 if (setpgid(0, sa->sa_pgroup) != 0) 102 return (errno); 103 } 104 105 /* Set scheduler policy */ 106 if (sa->sa_flags & POSIX_SPAWN_SETSCHEDULER) { 107 if (sched_setscheduler(0, sa->sa_schedpolicy, 108 &sa->sa_schedparam) != 0) 109 return (errno); 110 } else if (sa->sa_flags & POSIX_SPAWN_SETSCHEDPARAM) { 111 if (sched_setparam(0, &sa->sa_schedparam) != 0) 112 return (errno); 113 } 114 115 /* Reset user ID's */ 116 if (sa->sa_flags & POSIX_SPAWN_RESETIDS) { 117 if (setegid(getgid()) != 0) 118 return (errno); 119 if (seteuid(getuid()) != 0) 120 return (errno); 121 } 122 123 /* 124 * Set signal masks/defaults. 125 * Use unwrapped syscall, libthr is in undefined state after vfork(). 126 */ 127 if (sa->sa_flags & POSIX_SPAWN_SETSIGMASK) { 128 __sys_sigprocmask(SIG_SETMASK, &sa->sa_sigmask, NULL); 129 } 130 131 if (sa->sa_flags & POSIX_SPAWN_SETSIGDEF) { 132 for (i = 1; i <= _SIG_MAXSIG; i++) { 133 if (sigismember(&sa->sa_sigdefault, i)) 134 if (__sys_sigaction(i, &sigact, NULL) != 0) 135 return (errno); 136 } 137 } 138 139 return (0); 140 } 141 142 static int 143 process_file_actions_entry(posix_spawn_file_actions_entry_t *fae) 144 { 145 int fd, saved_errno; 146 147 switch (fae->fae_action) { 148 case FAE_OPEN: 149 /* Perform an open(), make it use the right fd */ 150 fd = _open(fae->fae_path, fae->fae_oflag, fae->fae_mode); 151 if (fd < 0) 152 return (errno); 153 if (fd != fae->fae_fildes) { 154 if (_dup2(fd, fae->fae_fildes) == -1) { 155 saved_errno = errno; 156 (void)_close(fd); 157 return (saved_errno); 158 } 159 if (_close(fd) != 0) { 160 if (errno == EBADF) 161 return (EBADF); 162 } 163 } 164 if (_fcntl(fae->fae_fildes, F_SETFD, 0) == -1) 165 return (errno); 166 break; 167 case FAE_DUP2: 168 /* Perform a dup2() */ 169 if (_dup2(fae->fae_fildes, fae->fae_newfildes) == -1) 170 return (errno); 171 if (_fcntl(fae->fae_newfildes, F_SETFD, 0) == -1) 172 return (errno); 173 break; 174 case FAE_CLOSE: 175 /* Perform a close(), do not fail if already closed */ 176 (void)_close(fae->fae_fildes); 177 break; 178 } 179 return (0); 180 } 181 182 static int 183 process_file_actions(const posix_spawn_file_actions_t fa) 184 { 185 posix_spawn_file_actions_entry_t *fae; 186 int error; 187 188 /* Replay all file descriptor modifications */ 189 STAILQ_FOREACH(fae, &fa->fa_list, fae_list) { 190 error = process_file_actions_entry(fae); 191 if (error) 192 return (error); 193 } 194 return (0); 195 } 196 197 struct posix_spawn_args { 198 const char *path; 199 const posix_spawn_file_actions_t *fa; 200 const posix_spawnattr_t *sa; 201 char * const * argv; 202 char * const * envp; 203 int use_env_path; 204 volatile int error; 205 }; 206 207 #if defined(__i386__) || defined(__amd64__) 208 #define _RFORK_THREAD_STACK_SIZE 4096 209 #endif 210 211 static int 212 _posix_spawn_thr(void *data) 213 { 214 struct posix_spawn_args *psa; 215 char * const *envp; 216 217 psa = data; 218 if (psa->sa != NULL) { 219 psa->error = process_spawnattr(*psa->sa); 220 if (psa->error) 221 _exit(127); 222 } 223 if (psa->fa != NULL) { 224 psa->error = process_file_actions(*psa->fa); 225 if (psa->error) 226 _exit(127); 227 } 228 envp = psa->envp != NULL ? psa->envp : environ; 229 if (psa->use_env_path) 230 _execvpe(psa->path, psa->argv, envp); 231 else 232 _execve(psa->path, psa->argv, envp); 233 psa->error = errno; 234 235 /* This is called in such a way that it must not exit. */ 236 _exit(127); 237 } 238 239 static int 240 do_posix_spawn(pid_t *pid, const char *path, 241 const posix_spawn_file_actions_t *fa, 242 const posix_spawnattr_t *sa, 243 char * const argv[], char * const envp[], int use_env_path) 244 { 245 struct posix_spawn_args psa; 246 pid_t p; 247 #ifdef _RFORK_THREAD_STACK_SIZE 248 char *stack; 249 250 stack = malloc(_RFORK_THREAD_STACK_SIZE); 251 if (stack == NULL) 252 return (ENOMEM); 253 #endif 254 psa.path = path; 255 psa.fa = fa; 256 psa.sa = sa; 257 psa.argv = argv; 258 psa.envp = envp; 259 psa.use_env_path = use_env_path; 260 psa.error = 0; 261 262 /* 263 * Passing RFSPAWN to rfork(2) gives us effectively a vfork that drops 264 * non-ignored signal handlers. We'll fall back to the slightly less 265 * ideal vfork(2) if we get an EINVAL from rfork -- this should only 266 * happen with newer libc on older kernel that doesn't accept 267 * RFSPAWN. 268 */ 269 #ifdef _RFORK_THREAD_STACK_SIZE 270 /* 271 * x86 stores the return address on the stack, so rfork(2) cannot work 272 * as-is because the child would clobber the return address om the 273 * parent. Because of this, we must use rfork_thread instead while 274 * almost every other arch stores the return address in a register. 275 */ 276 p = rfork_thread(RFSPAWN, stack + _RFORK_THREAD_STACK_SIZE, 277 _posix_spawn_thr, &psa); 278 free(stack); 279 #else 280 p = rfork(RFSPAWN); 281 if (p == 0) 282 /* _posix_spawn_thr does not return */ 283 _posix_spawn_thr(&psa); 284 #endif 285 /* 286 * The above block should leave us in a state where we've either 287 * succeeded and we're ready to process the results, or we need to 288 * fallback to vfork() if the kernel didn't like RFSPAWN. 289 */ 290 291 if (p == -1 && errno == EINVAL) { 292 p = vfork(); 293 if (p == 0) 294 /* _posix_spawn_thr does not return */ 295 _posix_spawn_thr(&psa); 296 } 297 if (p == -1) 298 return (errno); 299 if (psa.error != 0) 300 /* Failed; ready to reap */ 301 _waitpid(p, NULL, WNOHANG); 302 else if (pid != NULL) 303 /* exec succeeded */ 304 *pid = p; 305 return (psa.error); 306 } 307 308 int 309 posix_spawn(pid_t *pid, const char *path, 310 const posix_spawn_file_actions_t *fa, 311 const posix_spawnattr_t *sa, 312 char * const argv[], char * const envp[]) 313 { 314 return do_posix_spawn(pid, path, fa, sa, argv, envp, 0); 315 } 316 317 int 318 posix_spawnp(pid_t *pid, const char *path, 319 const posix_spawn_file_actions_t *fa, 320 const posix_spawnattr_t *sa, 321 char * const argv[], char * const envp[]) 322 { 323 return do_posix_spawn(pid, path, fa, sa, argv, envp, 1); 324 } 325 326 /* 327 * File descriptor actions 328 */ 329 330 int 331 posix_spawn_file_actions_init(posix_spawn_file_actions_t *ret) 332 { 333 posix_spawn_file_actions_t fa; 334 335 fa = malloc(sizeof(struct __posix_spawn_file_actions)); 336 if (fa == NULL) 337 return (-1); 338 339 STAILQ_INIT(&fa->fa_list); 340 *ret = fa; 341 return (0); 342 } 343 344 int 345 posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *fa) 346 { 347 posix_spawn_file_actions_entry_t *fae; 348 349 while ((fae = STAILQ_FIRST(&(*fa)->fa_list)) != NULL) { 350 /* Remove file action entry from the queue */ 351 STAILQ_REMOVE_HEAD(&(*fa)->fa_list, fae_list); 352 353 /* Deallocate file action entry */ 354 if (fae->fae_action == FAE_OPEN) 355 free(fae->fae_path); 356 free(fae); 357 } 358 359 free(*fa); 360 return (0); 361 } 362 363 int 364 posix_spawn_file_actions_addopen(posix_spawn_file_actions_t * __restrict fa, 365 int fildes, const char * __restrict path, int oflag, mode_t mode) 366 { 367 posix_spawn_file_actions_entry_t *fae; 368 int error; 369 370 if (fildes < 0) 371 return (EBADF); 372 373 /* Allocate object */ 374 fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 375 if (fae == NULL) 376 return (errno); 377 378 /* Set values and store in queue */ 379 fae->fae_action = FAE_OPEN; 380 fae->fae_path = strdup(path); 381 if (fae->fae_path == NULL) { 382 error = errno; 383 free(fae); 384 return (error); 385 } 386 fae->fae_fildes = fildes; 387 fae->fae_oflag = oflag; 388 fae->fae_mode = mode; 389 390 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 391 return (0); 392 } 393 394 int 395 posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *fa, 396 int fildes, int newfildes) 397 { 398 posix_spawn_file_actions_entry_t *fae; 399 400 if (fildes < 0 || newfildes < 0) 401 return (EBADF); 402 403 /* Allocate object */ 404 fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 405 if (fae == NULL) 406 return (errno); 407 408 /* Set values and store in queue */ 409 fae->fae_action = FAE_DUP2; 410 fae->fae_fildes = fildes; 411 fae->fae_newfildes = newfildes; 412 413 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 414 return (0); 415 } 416 417 int 418 posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *fa, 419 int fildes) 420 { 421 posix_spawn_file_actions_entry_t *fae; 422 423 if (fildes < 0) 424 return (EBADF); 425 426 /* Allocate object */ 427 fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 428 if (fae == NULL) 429 return (errno); 430 431 /* Set values and store in queue */ 432 fae->fae_action = FAE_CLOSE; 433 fae->fae_fildes = fildes; 434 435 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 436 return (0); 437 } 438 439 /* 440 * Spawn attributes 441 */ 442 443 int 444 posix_spawnattr_init(posix_spawnattr_t *ret) 445 { 446 posix_spawnattr_t sa; 447 448 sa = calloc(1, sizeof(struct __posix_spawnattr)); 449 if (sa == NULL) 450 return (errno); 451 452 /* Set defaults as specified by POSIX, cleared above */ 453 *ret = sa; 454 return (0); 455 } 456 457 int 458 posix_spawnattr_destroy(posix_spawnattr_t *sa) 459 { 460 free(*sa); 461 return (0); 462 } 463 464 int 465 posix_spawnattr_getflags(const posix_spawnattr_t * __restrict sa, 466 short * __restrict flags) 467 { 468 *flags = (*sa)->sa_flags; 469 return (0); 470 } 471 472 int 473 posix_spawnattr_getpgroup(const posix_spawnattr_t * __restrict sa, 474 pid_t * __restrict pgroup) 475 { 476 *pgroup = (*sa)->sa_pgroup; 477 return (0); 478 } 479 480 int 481 posix_spawnattr_getschedparam(const posix_spawnattr_t * __restrict sa, 482 struct sched_param * __restrict schedparam) 483 { 484 *schedparam = (*sa)->sa_schedparam; 485 return (0); 486 } 487 488 int 489 posix_spawnattr_getschedpolicy(const posix_spawnattr_t * __restrict sa, 490 int * __restrict schedpolicy) 491 { 492 *schedpolicy = (*sa)->sa_schedpolicy; 493 return (0); 494 } 495 496 int 497 posix_spawnattr_getsigdefault(const posix_spawnattr_t * __restrict sa, 498 sigset_t * __restrict sigdefault) 499 { 500 *sigdefault = (*sa)->sa_sigdefault; 501 return (0); 502 } 503 504 int 505 posix_spawnattr_getsigmask(const posix_spawnattr_t * __restrict sa, 506 sigset_t * __restrict sigmask) 507 { 508 *sigmask = (*sa)->sa_sigmask; 509 return (0); 510 } 511 512 int 513 posix_spawnattr_setflags(posix_spawnattr_t *sa, short flags) 514 { 515 (*sa)->sa_flags = flags; 516 return (0); 517 } 518 519 int 520 posix_spawnattr_setpgroup(posix_spawnattr_t *sa, pid_t pgroup) 521 { 522 (*sa)->sa_pgroup = pgroup; 523 return (0); 524 } 525 526 int 527 posix_spawnattr_setschedparam(posix_spawnattr_t * __restrict sa, 528 const struct sched_param * __restrict schedparam) 529 { 530 (*sa)->sa_schedparam = *schedparam; 531 return (0); 532 } 533 534 int 535 posix_spawnattr_setschedpolicy(posix_spawnattr_t *sa, int schedpolicy) 536 { 537 (*sa)->sa_schedpolicy = schedpolicy; 538 return (0); 539 } 540 541 int 542 posix_spawnattr_setsigdefault(posix_spawnattr_t * __restrict sa, 543 const sigset_t * __restrict sigdefault) 544 { 545 (*sa)->sa_sigdefault = *sigdefault; 546 return (0); 547 } 548 549 int 550 posix_spawnattr_setsigmask(posix_spawnattr_t * __restrict sa, 551 const sigset_t * __restrict sigmask) 552 { 553 (*sa)->sa_sigmask = *sigmask; 554 return (0); 555 } 556