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