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