1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 "namespace.h" 30 #include <sys/param.h> 31 #include <sys/queue.h> 32 #include <sys/wait.h> 33 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <sched.h> 37 #include <spawn.h> 38 #include <signal.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include "un-namespace.h" 43 #include "libc_private.h" 44 45 struct __posix_spawnattr { 46 short sa_flags; 47 pid_t sa_pgroup; 48 struct sched_param sa_schedparam; 49 int sa_schedpolicy; 50 sigset_t sa_sigdefault; 51 sigset_t sa_sigmask; 52 }; 53 54 struct __posix_spawn_file_actions { 55 STAILQ_HEAD(, __posix_spawn_file_actions_entry) fa_list; 56 }; 57 58 typedef struct __posix_spawn_file_actions_entry { 59 STAILQ_ENTRY(__posix_spawn_file_actions_entry) fae_list; 60 enum { 61 FAE_OPEN, 62 FAE_DUP2, 63 FAE_CLOSE, 64 FAE_CHDIR, 65 FAE_FCHDIR, 66 FAE_CLOSEFROM, 67 } fae_action; 68 69 int fae_fildes; 70 union { 71 struct { 72 char *path; 73 #define fae_path fae_data.open.path 74 int oflag; 75 #define fae_oflag fae_data.open.oflag 76 mode_t mode; 77 #define fae_mode fae_data.open.mode 78 } open; 79 struct { 80 int newfildes; 81 #define fae_newfildes fae_data.dup2.newfildes 82 } dup2; 83 } fae_data; 84 } posix_spawn_file_actions_entry_t; 85 86 /* 87 * Spawn routines 88 */ 89 90 static int 91 process_spawnattr(const posix_spawnattr_t sa) 92 { 93 struct sigaction sigact = { .sa_flags = 0, .sa_handler = SIG_DFL }; 94 int i; 95 96 /* 97 * POSIX doesn't really describe in which order everything 98 * should be set. We'll just set them in the order in which they 99 * are mentioned. 100 */ 101 102 /* Set process group */ 103 if (sa->sa_flags & POSIX_SPAWN_SETPGROUP) { 104 if (setpgid(0, sa->sa_pgroup) != 0) 105 return (errno); 106 } 107 108 /* Set scheduler policy */ 109 if (sa->sa_flags & POSIX_SPAWN_SETSCHEDULER) { 110 if (sched_setscheduler(0, sa->sa_schedpolicy, 111 &sa->sa_schedparam) != 0) 112 return (errno); 113 } else if (sa->sa_flags & POSIX_SPAWN_SETSCHEDPARAM) { 114 if (sched_setparam(0, &sa->sa_schedparam) != 0) 115 return (errno); 116 } 117 118 /* Reset user ID's */ 119 if (sa->sa_flags & POSIX_SPAWN_RESETIDS) { 120 if (setegid(getgid()) != 0) 121 return (errno); 122 if (seteuid(getuid()) != 0) 123 return (errno); 124 } 125 126 /* 127 * Set signal masks/defaults. 128 * Use unwrapped syscall, libthr is in undefined state after vfork(). 129 */ 130 if (sa->sa_flags & POSIX_SPAWN_SETSIGMASK) { 131 __sys_sigprocmask(SIG_SETMASK, &sa->sa_sigmask, NULL); 132 } 133 134 if (sa->sa_flags & POSIX_SPAWN_SETSIGDEF) { 135 for (i = 1; i <= _SIG_MAXSIG; i++) { 136 if (sigismember(&sa->sa_sigdefault, i)) 137 if (__sys_sigaction(i, &sigact, NULL) != 0) 138 return (errno); 139 } 140 } 141 142 return (0); 143 } 144 145 static int 146 process_file_actions_entry(posix_spawn_file_actions_entry_t *fae) 147 { 148 int fd, saved_errno; 149 150 switch (fae->fae_action) { 151 case FAE_OPEN: 152 /* Perform an open(), make it use the right fd */ 153 fd = _open(fae->fae_path, fae->fae_oflag, fae->fae_mode); 154 if (fd < 0) 155 return (errno); 156 if (fd != fae->fae_fildes) { 157 if (_dup2(fd, fae->fae_fildes) == -1) { 158 saved_errno = errno; 159 (void)_close(fd); 160 return (saved_errno); 161 } 162 if (_close(fd) != 0) { 163 if (errno == EBADF) 164 return (EBADF); 165 } 166 } 167 if (_fcntl(fae->fae_fildes, F_SETFD, 0) == -1) 168 return (errno); 169 break; 170 case FAE_DUP2: 171 /* Perform a dup2() */ 172 if (_dup2(fae->fae_fildes, fae->fae_newfildes) == -1) 173 return (errno); 174 if (_fcntl(fae->fae_newfildes, F_SETFD, 0) == -1) 175 return (errno); 176 break; 177 case FAE_CLOSE: 178 /* Perform a close(), do not fail if already closed */ 179 (void)_close(fae->fae_fildes); 180 break; 181 case FAE_CHDIR: 182 if (chdir(fae->fae_path) != 0) 183 return (errno); 184 break; 185 case FAE_FCHDIR: 186 if (fchdir(fae->fae_fildes) != 0) 187 return (errno); 188 break; 189 case FAE_CLOSEFROM: 190 closefrom(fae->fae_fildes); 191 break; 192 } 193 return (0); 194 } 195 196 static int 197 process_file_actions(const posix_spawn_file_actions_t fa) 198 { 199 posix_spawn_file_actions_entry_t *fae; 200 int error; 201 202 /* Replay all file descriptor modifications */ 203 STAILQ_FOREACH(fae, &fa->fa_list, fae_list) { 204 error = process_file_actions_entry(fae); 205 if (error) 206 return (error); 207 } 208 return (0); 209 } 210 211 struct posix_spawn_args { 212 const char *path; 213 const posix_spawn_file_actions_t *fa; 214 const posix_spawnattr_t *sa; 215 char * const * argv; 216 char * const * envp; 217 int use_env_path; 218 volatile int error; 219 }; 220 221 #define PSPAWN_STACK_ALIGNMENT 16 222 #define PSPAWN_STACK_ALIGNBYTES (PSPAWN_STACK_ALIGNMENT - 1) 223 #define PSPAWN_STACK_ALIGN(sz) \ 224 (((sz) + PSPAWN_STACK_ALIGNBYTES) & ~PSPAWN_STACK_ALIGNBYTES) 225 226 #if defined(__i386__) || defined(__amd64__) 227 /* 228 * Below we'll assume that _RFORK_THREAD_STACK_SIZE is appropriately aligned for 229 * the posix_spawn() case where we do not end up calling execvpe and won't ever 230 * try to allocate space on the stack for argv[]. 231 */ 232 #define _RFORK_THREAD_STACK_SIZE 4096 233 _Static_assert((_RFORK_THREAD_STACK_SIZE % PSPAWN_STACK_ALIGNMENT) == 0, 234 "Inappropriate stack size alignment"); 235 #endif 236 237 static int 238 _posix_spawn_thr(void *data) 239 { 240 struct posix_spawn_args *psa; 241 char * const *envp; 242 243 psa = data; 244 if (psa->sa != NULL) { 245 psa->error = process_spawnattr(*psa->sa); 246 if (psa->error) 247 _exit(127); 248 } 249 if (psa->fa != NULL) { 250 psa->error = process_file_actions(*psa->fa); 251 if (psa->error) 252 _exit(127); 253 } 254 envp = psa->envp != NULL ? psa->envp : environ; 255 if (psa->use_env_path) 256 execvpe(psa->path, psa->argv, envp); 257 else 258 _execve(psa->path, psa->argv, envp); 259 psa->error = errno; 260 261 /* This is called in such a way that it must not exit. */ 262 _exit(127); 263 } 264 265 static int 266 do_posix_spawn(pid_t *pid, const char *path, 267 const posix_spawn_file_actions_t *fa, 268 const posix_spawnattr_t *sa, 269 char * const argv[], char * const envp[], int use_env_path) 270 { 271 struct posix_spawn_args psa; 272 pid_t p; 273 #ifdef _RFORK_THREAD_STACK_SIZE 274 char *stack; 275 size_t cnt, stacksz; 276 277 stacksz = _RFORK_THREAD_STACK_SIZE; 278 if (use_env_path) { 279 /* 280 * We need to make sure we have enough room on the stack for the 281 * potential alloca() in execvPe if it gets kicked back an 282 * ENOEXEC from execve(2), plus the original buffer we gave 283 * ourselves; this protects us in the event that the caller 284 * intentionally or inadvertently supplies enough arguments to 285 * make us blow past the stack we've allocated from it. 286 */ 287 for (cnt = 0; argv[cnt] != NULL; ++cnt) 288 ; 289 stacksz += MAX(3, cnt + 2) * sizeof(char *); 290 stacksz = PSPAWN_STACK_ALIGN(stacksz); 291 } 292 293 /* 294 * aligned_alloc is not safe to use here, because we can't guarantee 295 * that aligned_alloc and free will be provided by the same 296 * implementation. We've actively hit at least one application that 297 * will provide its own malloc/free but not aligned_alloc leading to 298 * a free by the wrong allocator. 299 */ 300 stack = malloc(stacksz); 301 if (stack == NULL) 302 return (ENOMEM); 303 stacksz = (((uintptr_t)stack + stacksz) & ~PSPAWN_STACK_ALIGNBYTES) - 304 (uintptr_t)stack; 305 #endif 306 psa.path = path; 307 psa.fa = fa; 308 psa.sa = sa; 309 psa.argv = argv; 310 psa.envp = envp; 311 psa.use_env_path = use_env_path; 312 psa.error = 0; 313 314 /* 315 * Passing RFSPAWN to rfork(2) gives us effectively a vfork that drops 316 * non-ignored signal handlers. We'll fall back to the slightly less 317 * ideal vfork(2) if we get an EINVAL from rfork -- this should only 318 * happen with newer libc on older kernel that doesn't accept 319 * RFSPAWN. 320 */ 321 #ifdef _RFORK_THREAD_STACK_SIZE 322 /* 323 * x86 stores the return address on the stack, so rfork(2) cannot work 324 * as-is because the child would clobber the return address om the 325 * parent. Because of this, we must use rfork_thread instead while 326 * almost every other arch stores the return address in a register. 327 */ 328 p = rfork_thread(RFSPAWN, stack + stacksz, _posix_spawn_thr, &psa); 329 free(stack); 330 #else 331 p = rfork(RFSPAWN); 332 if (p == 0) 333 /* _posix_spawn_thr does not return */ 334 _posix_spawn_thr(&psa); 335 #endif 336 /* 337 * The above block should leave us in a state where we've either 338 * succeeded and we're ready to process the results, or we need to 339 * fallback to vfork() if the kernel didn't like RFSPAWN. 340 */ 341 342 if (p == -1 && errno == EINVAL) { 343 p = vfork(); 344 if (p == 0) 345 /* _posix_spawn_thr does not return */ 346 _posix_spawn_thr(&psa); 347 } 348 if (p == -1) 349 return (errno); 350 if (psa.error != 0) 351 /* Failed; ready to reap */ 352 _waitpid(p, NULL, WNOHANG); 353 else if (pid != NULL) 354 /* exec succeeded */ 355 *pid = p; 356 return (psa.error); 357 } 358 359 int 360 posix_spawn(pid_t *pid, const char *path, 361 const posix_spawn_file_actions_t *fa, 362 const posix_spawnattr_t *sa, 363 char * const argv[], char * const envp[]) 364 { 365 return (do_posix_spawn(pid, path, fa, sa, argv, envp, 0)); 366 } 367 368 int 369 posix_spawnp(pid_t *pid, const char *path, 370 const posix_spawn_file_actions_t *fa, 371 const posix_spawnattr_t *sa, 372 char * const argv[], char * const envp[]) 373 { 374 return (do_posix_spawn(pid, path, fa, sa, argv, envp, 1)); 375 } 376 377 /* 378 * File descriptor actions 379 */ 380 381 int 382 posix_spawn_file_actions_init(posix_spawn_file_actions_t *ret) 383 { 384 posix_spawn_file_actions_t fa; 385 386 fa = malloc(sizeof(struct __posix_spawn_file_actions)); 387 if (fa == NULL) 388 return (-1); 389 390 STAILQ_INIT(&fa->fa_list); 391 *ret = fa; 392 return (0); 393 } 394 395 int 396 posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *fa) 397 { 398 posix_spawn_file_actions_entry_t *fae; 399 400 while ((fae = STAILQ_FIRST(&(*fa)->fa_list)) != NULL) { 401 /* Remove file action entry from the queue */ 402 STAILQ_REMOVE_HEAD(&(*fa)->fa_list, fae_list); 403 404 /* Deallocate file action entry */ 405 if (fae->fae_action == FAE_OPEN || 406 fae->fae_action == FAE_CHDIR) 407 free(fae->fae_path); 408 free(fae); 409 } 410 411 free(*fa); 412 return (0); 413 } 414 415 int 416 posix_spawn_file_actions_addopen(posix_spawn_file_actions_t * __restrict fa, 417 int fildes, const char * __restrict path, int oflag, mode_t mode) 418 { 419 posix_spawn_file_actions_entry_t *fae; 420 int error; 421 422 if (fildes < 0) 423 return (EBADF); 424 425 /* Allocate object */ 426 fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 427 if (fae == NULL) 428 return (errno); 429 430 /* Set values and store in queue */ 431 fae->fae_action = FAE_OPEN; 432 fae->fae_path = strdup(path); 433 if (fae->fae_path == NULL) { 434 error = errno; 435 free(fae); 436 return (error); 437 } 438 fae->fae_fildes = fildes; 439 fae->fae_oflag = oflag; 440 fae->fae_mode = mode; 441 442 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 443 return (0); 444 } 445 446 int 447 posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *fa, 448 int fildes, int newfildes) 449 { 450 posix_spawn_file_actions_entry_t *fae; 451 452 if (fildes < 0 || newfildes < 0) 453 return (EBADF); 454 455 /* Allocate object */ 456 fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 457 if (fae == NULL) 458 return (errno); 459 460 /* Set values and store in queue */ 461 fae->fae_action = FAE_DUP2; 462 fae->fae_fildes = fildes; 463 fae->fae_newfildes = newfildes; 464 465 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 466 return (0); 467 } 468 469 int 470 posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *fa, 471 int fildes) 472 { 473 posix_spawn_file_actions_entry_t *fae; 474 475 if (fildes < 0) 476 return (EBADF); 477 478 /* Allocate object */ 479 fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 480 if (fae == NULL) 481 return (errno); 482 483 /* Set values and store in queue */ 484 fae->fae_action = FAE_CLOSE; 485 fae->fae_fildes = fildes; 486 487 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 488 return (0); 489 } 490 491 int 492 posix_spawn_file_actions_addchdir_np(posix_spawn_file_actions_t * 493 __restrict fa, const char *__restrict path) 494 { 495 posix_spawn_file_actions_entry_t *fae; 496 int error; 497 498 fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 499 if (fae == NULL) 500 return (errno); 501 502 fae->fae_action = FAE_CHDIR; 503 fae->fae_path = strdup(path); 504 if (fae->fae_path == NULL) { 505 error = errno; 506 free(fae); 507 return (error); 508 } 509 510 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 511 return (0); 512 } 513 514 int 515 posix_spawn_file_actions_addfchdir_np(posix_spawn_file_actions_t *__restrict fa, 516 int fildes) 517 { 518 posix_spawn_file_actions_entry_t *fae; 519 520 if (fildes < 0) 521 return (EBADF); 522 523 /* Allocate object */ 524 fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 525 if (fae == NULL) 526 return (errno); 527 528 fae->fae_action = FAE_FCHDIR; 529 fae->fae_fildes = fildes; 530 531 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 532 return (0); 533 } 534 535 int 536 posix_spawn_file_actions_addclosefrom_np (posix_spawn_file_actions_t * 537 __restrict fa, int from) 538 { 539 posix_spawn_file_actions_entry_t *fae; 540 541 if (from < 0) 542 return (EBADF); 543 544 /* Allocate object */ 545 fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 546 if (fae == NULL) 547 return (errno); 548 549 fae->fae_action = FAE_CLOSEFROM; 550 fae->fae_fildes = from; 551 552 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 553 return (0); 554 } 555 556 /* 557 * Spawn attributes 558 */ 559 560 int 561 posix_spawnattr_init(posix_spawnattr_t *ret) 562 { 563 posix_spawnattr_t sa; 564 565 sa = calloc(1, sizeof(struct __posix_spawnattr)); 566 if (sa == NULL) 567 return (errno); 568 569 /* Set defaults as specified by POSIX, cleared above */ 570 *ret = sa; 571 return (0); 572 } 573 574 int 575 posix_spawnattr_destroy(posix_spawnattr_t *sa) 576 { 577 free(*sa); 578 return (0); 579 } 580 581 int 582 posix_spawnattr_getflags(const posix_spawnattr_t * __restrict sa, 583 short * __restrict flags) 584 { 585 *flags = (*sa)->sa_flags; 586 return (0); 587 } 588 589 int 590 posix_spawnattr_getpgroup(const posix_spawnattr_t * __restrict sa, 591 pid_t * __restrict pgroup) 592 { 593 *pgroup = (*sa)->sa_pgroup; 594 return (0); 595 } 596 597 int 598 posix_spawnattr_getschedparam(const posix_spawnattr_t * __restrict sa, 599 struct sched_param * __restrict schedparam) 600 { 601 *schedparam = (*sa)->sa_schedparam; 602 return (0); 603 } 604 605 int 606 posix_spawnattr_getschedpolicy(const posix_spawnattr_t * __restrict sa, 607 int * __restrict schedpolicy) 608 { 609 *schedpolicy = (*sa)->sa_schedpolicy; 610 return (0); 611 } 612 613 int 614 posix_spawnattr_getsigdefault(const posix_spawnattr_t * __restrict sa, 615 sigset_t * __restrict sigdefault) 616 { 617 *sigdefault = (*sa)->sa_sigdefault; 618 return (0); 619 } 620 621 int 622 posix_spawnattr_getsigmask(const posix_spawnattr_t * __restrict sa, 623 sigset_t * __restrict sigmask) 624 { 625 *sigmask = (*sa)->sa_sigmask; 626 return (0); 627 } 628 629 int 630 posix_spawnattr_setflags(posix_spawnattr_t *sa, short flags) 631 { 632 (*sa)->sa_flags = flags; 633 return (0); 634 } 635 636 int 637 posix_spawnattr_setpgroup(posix_spawnattr_t *sa, pid_t pgroup) 638 { 639 (*sa)->sa_pgroup = pgroup; 640 return (0); 641 } 642 643 int 644 posix_spawnattr_setschedparam(posix_spawnattr_t * __restrict sa, 645 const struct sched_param * __restrict schedparam) 646 { 647 (*sa)->sa_schedparam = *schedparam; 648 return (0); 649 } 650 651 int 652 posix_spawnattr_setschedpolicy(posix_spawnattr_t *sa, int schedpolicy) 653 { 654 (*sa)->sa_schedpolicy = schedpolicy; 655 return (0); 656 } 657 658 int 659 posix_spawnattr_setsigdefault(posix_spawnattr_t * __restrict sa, 660 const sigset_t * __restrict sigdefault) 661 { 662 (*sa)->sa_sigdefault = *sigdefault; 663 return (0); 664 } 665 666 int 667 posix_spawnattr_setsigmask(posix_spawnattr_t * __restrict sa, 668 const sigset_t * __restrict sigmask) 669 { 670 (*sa)->sa_sigmask = *sigmask; 671 return (0); 672 } 673