1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 */ 21 22 #include "uv.h" 23 #include "internal.h" 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <assert.h> 28 #include <errno.h> 29 #include <signal.h> 30 #include <string.h> 31 32 #include <sys/types.h> 33 #include <sys/wait.h> 34 #include <unistd.h> 35 #include <fcntl.h> 36 #include <poll.h> 37 38 #if defined(__APPLE__) && !TARGET_OS_IPHONE 39 # include <spawn.h> 40 # include <paths.h> 41 # include <sys/kauth.h> 42 # include <sys/types.h> 43 # include <sys/sysctl.h> 44 # include <dlfcn.h> 45 # include <crt_externs.h> 46 # include <xlocale.h> 47 # define environ (*_NSGetEnviron()) 48 49 /* macOS 10.14 back does not define this constant */ 50 # ifndef POSIX_SPAWN_SETSID 51 # define POSIX_SPAWN_SETSID 1024 52 # endif 53 54 #else 55 extern char **environ; 56 #endif 57 58 #if defined(__linux__) || defined(__GLIBC__) 59 # include <grp.h> 60 #endif 61 62 #if defined(__MVS__) 63 # include "zos-base.h" 64 #endif 65 66 #if defined(__APPLE__) || \ 67 defined(__DragonFly__) || \ 68 defined(__FreeBSD__) || \ 69 defined(__NetBSD__) || \ 70 defined(__OpenBSD__) 71 #include <sys/event.h> 72 #else 73 #define UV_USE_SIGCHLD 74 #endif 75 76 77 #ifdef UV_USE_SIGCHLD uv__chld(uv_signal_t * handle,int signum)78 static void uv__chld(uv_signal_t* handle, int signum) { 79 assert(signum == SIGCHLD); 80 uv__wait_children(handle->loop); 81 } 82 #endif 83 uv__wait_children(uv_loop_t * loop)84 void uv__wait_children(uv_loop_t* loop) { 85 uv_process_t* process; 86 int exit_status; 87 int term_signal; 88 int status; 89 int options; 90 pid_t pid; 91 QUEUE pending; 92 QUEUE* q; 93 QUEUE* h; 94 95 QUEUE_INIT(&pending); 96 97 h = &loop->process_handles; 98 q = QUEUE_HEAD(h); 99 while (q != h) { 100 process = QUEUE_DATA(q, uv_process_t, queue); 101 q = QUEUE_NEXT(q); 102 103 #ifndef UV_USE_SIGCHLD 104 if ((process->flags & UV_HANDLE_REAP) == 0) 105 continue; 106 options = 0; 107 process->flags &= ~UV_HANDLE_REAP; 108 #else 109 options = WNOHANG; 110 #endif 111 112 do 113 pid = waitpid(process->pid, &status, options); 114 while (pid == -1 && errno == EINTR); 115 116 #ifdef UV_USE_SIGCHLD 117 if (pid == 0) /* Not yet exited */ 118 continue; 119 #endif 120 121 if (pid == -1) { 122 if (errno != ECHILD) 123 abort(); 124 /* The child died, and we missed it. This probably means someone else 125 * stole the waitpid from us. Handle this by not handling it at all. */ 126 continue; 127 } 128 129 assert(pid == process->pid); 130 process->status = status; 131 QUEUE_REMOVE(&process->queue); 132 QUEUE_INSERT_TAIL(&pending, &process->queue); 133 } 134 135 h = &pending; 136 q = QUEUE_HEAD(h); 137 while (q != h) { 138 process = QUEUE_DATA(q, uv_process_t, queue); 139 q = QUEUE_NEXT(q); 140 141 QUEUE_REMOVE(&process->queue); 142 QUEUE_INIT(&process->queue); 143 uv__handle_stop(process); 144 145 if (process->exit_cb == NULL) 146 continue; 147 148 exit_status = 0; 149 if (WIFEXITED(process->status)) 150 exit_status = WEXITSTATUS(process->status); 151 152 term_signal = 0; 153 if (WIFSIGNALED(process->status)) 154 term_signal = WTERMSIG(process->status); 155 156 process->exit_cb(process, exit_status, term_signal); 157 } 158 assert(QUEUE_EMPTY(&pending)); 159 } 160 161 /* 162 * Used for initializing stdio streams like options.stdin_stream. Returns 163 * zero on success. See also the cleanup section in uv_spawn(). 164 */ uv__process_init_stdio(uv_stdio_container_t * container,int fds[2])165 static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { 166 int mask; 167 int fd; 168 169 mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM; 170 171 switch (container->flags & mask) { 172 case UV_IGNORE: 173 return 0; 174 175 case UV_CREATE_PIPE: 176 assert(container->data.stream != NULL); 177 if (container->data.stream->type != UV_NAMED_PIPE) 178 return UV_EINVAL; 179 else 180 return uv_socketpair(SOCK_STREAM, 0, fds, 0, 0); 181 182 case UV_INHERIT_FD: 183 case UV_INHERIT_STREAM: 184 if (container->flags & UV_INHERIT_FD) 185 fd = container->data.fd; 186 else 187 fd = uv__stream_fd(container->data.stream); 188 189 if (fd == -1) 190 return UV_EINVAL; 191 192 fds[1] = fd; 193 return 0; 194 195 default: 196 assert(0 && "Unexpected flags"); 197 return UV_EINVAL; 198 } 199 } 200 201 uv__process_open_stream(uv_stdio_container_t * container,int pipefds[2])202 static int uv__process_open_stream(uv_stdio_container_t* container, 203 int pipefds[2]) { 204 int flags; 205 int err; 206 207 if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0) 208 return 0; 209 210 err = uv__close(pipefds[1]); 211 if (err != 0) 212 abort(); 213 214 pipefds[1] = -1; 215 uv__nonblock(pipefds[0], 1); 216 217 flags = 0; 218 if (container->flags & UV_WRITABLE_PIPE) 219 flags |= UV_HANDLE_READABLE; 220 if (container->flags & UV_READABLE_PIPE) 221 flags |= UV_HANDLE_WRITABLE; 222 223 return uv__stream_open(container->data.stream, pipefds[0], flags); 224 } 225 226 uv__process_close_stream(uv_stdio_container_t * container)227 static void uv__process_close_stream(uv_stdio_container_t* container) { 228 if (!(container->flags & UV_CREATE_PIPE)) return; 229 uv__stream_close(container->data.stream); 230 } 231 232 uv__write_int(int fd,int val)233 static void uv__write_int(int fd, int val) { 234 ssize_t n; 235 236 do 237 n = write(fd, &val, sizeof(val)); 238 while (n == -1 && errno == EINTR); 239 240 /* The write might have failed (e.g. if the parent process has died), 241 * but we have nothing left but to _exit ourself now too. */ 242 _exit(127); 243 } 244 245 uv__write_errno(int error_fd)246 static void uv__write_errno(int error_fd) { 247 uv__write_int(error_fd, UV__ERR(errno)); 248 } 249 250 251 #if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) 252 /* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be 253 * avoided. Since this isn't called on those targets, the function 254 * doesn't even need to be defined for them. 255 */ uv__process_child_init(const uv_process_options_t * options,int stdio_count,int (* pipes)[2],int error_fd)256 static void uv__process_child_init(const uv_process_options_t* options, 257 int stdio_count, 258 int (*pipes)[2], 259 int error_fd) { 260 sigset_t signewset; 261 int close_fd; 262 int use_fd; 263 int fd; 264 int n; 265 266 /* Reset signal disposition first. Use a hard-coded limit because NSIG is not 267 * fixed on Linux: it's either 32, 34 or 64, depending on whether RT signals 268 * are enabled. We are not allowed to touch RT signal handlers, glibc uses 269 * them internally. 270 */ 271 for (n = 1; n < 32; n += 1) { 272 if (n == SIGKILL || n == SIGSTOP) 273 continue; /* Can't be changed. */ 274 275 #if defined(__HAIKU__) 276 if (n == SIGKILLTHR) 277 continue; /* Can't be changed. */ 278 #endif 279 280 if (SIG_ERR != signal(n, SIG_DFL)) 281 continue; 282 283 uv__write_errno(error_fd); 284 } 285 286 if (options->flags & UV_PROCESS_DETACHED) 287 setsid(); 288 289 /* First duplicate low numbered fds, since it's not safe to duplicate them, 290 * they could get replaced. Example: swapping stdout and stderr; without 291 * this fd 2 (stderr) would be duplicated into fd 1, thus making both 292 * stdout and stderr go to the same fd, which was not the intention. */ 293 for (fd = 0; fd < stdio_count; fd++) { 294 use_fd = pipes[fd][1]; 295 if (use_fd < 0 || use_fd >= fd) 296 continue; 297 #ifdef F_DUPFD_CLOEXEC /* POSIX 2008 */ 298 pipes[fd][1] = fcntl(use_fd, F_DUPFD_CLOEXEC, stdio_count); 299 #else 300 pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); 301 #endif 302 if (pipes[fd][1] == -1) 303 uv__write_errno(error_fd); 304 #ifndef F_DUPFD_CLOEXEC /* POSIX 2008 */ 305 n = uv__cloexec(pipes[fd][1], 1); 306 if (n) 307 uv__write_int(error_fd, n); 308 #endif 309 } 310 311 for (fd = 0; fd < stdio_count; fd++) { 312 close_fd = -1; 313 use_fd = pipes[fd][1]; 314 315 if (use_fd < 0) { 316 if (fd >= 3) 317 continue; 318 else { 319 /* Redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is 320 * set. */ 321 uv__close_nocheckstdio(fd); /* Free up fd, if it happens to be open. */ 322 use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); 323 close_fd = use_fd; 324 325 if (use_fd < 0) 326 uv__write_errno(error_fd); 327 } 328 } 329 330 if (fd == use_fd) { 331 if (close_fd == -1) { 332 n = uv__cloexec(use_fd, 0); 333 if (n) 334 uv__write_int(error_fd, n); 335 } 336 } 337 else { 338 fd = dup2(use_fd, fd); 339 } 340 341 if (fd == -1) 342 uv__write_errno(error_fd); 343 344 if (fd <= 2 && close_fd == -1) 345 uv__nonblock_fcntl(fd, 0); 346 347 if (close_fd >= stdio_count) 348 uv__close(close_fd); 349 } 350 351 if (options->cwd != NULL && chdir(options->cwd)) 352 uv__write_errno(error_fd); 353 354 if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { 355 /* When dropping privileges from root, the `setgroups` call will 356 * remove any extraneous groups. If we don't call this, then 357 * even though our uid has dropped, we may still have groups 358 * that enable us to do super-user things. This will fail if we 359 * aren't root, so don't bother checking the return value, this 360 * is just done as an optimistic privilege dropping function. 361 */ 362 SAVE_ERRNO(setgroups(0, NULL)); 363 } 364 365 if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) 366 uv__write_errno(error_fd); 367 368 if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) 369 uv__write_errno(error_fd); 370 371 if (options->env != NULL) 372 environ = options->env; 373 374 /* Reset signal mask just before exec. */ 375 sigemptyset(&signewset); 376 if (sigprocmask(SIG_SETMASK, &signewset, NULL) != 0) 377 abort(); 378 379 #ifdef __MVS__ 380 execvpe(options->file, options->args, environ); 381 #else 382 execvp(options->file, options->args); 383 #endif 384 385 uv__write_errno(error_fd); 386 } 387 #endif 388 389 390 #if defined(__APPLE__) && !TARGET_OS_IPHONE 391 typedef struct uv__posix_spawn_fncs_tag { 392 struct { 393 int (*addchdir_np)(const posix_spawn_file_actions_t *, const char *); 394 } file_actions; 395 } uv__posix_spawn_fncs_t; 396 397 398 static uv_once_t posix_spawn_init_once = UV_ONCE_INIT; 399 static uv__posix_spawn_fncs_t posix_spawn_fncs; 400 static int posix_spawn_can_use_setsid; 401 402 uv__spawn_init_posix_spawn_fncs(void)403 static void uv__spawn_init_posix_spawn_fncs(void) { 404 /* Try to locate all non-portable functions at runtime */ 405 posix_spawn_fncs.file_actions.addchdir_np = 406 dlsym(RTLD_DEFAULT, "posix_spawn_file_actions_addchdir_np"); 407 } 408 409 uv__spawn_init_can_use_setsid(void)410 static void uv__spawn_init_can_use_setsid(void) { 411 int which[] = {CTL_KERN, KERN_OSRELEASE}; 412 unsigned major; 413 unsigned minor; 414 unsigned patch; 415 char buf[256]; 416 size_t len; 417 418 len = sizeof(buf); 419 if (sysctl(which, ARRAY_SIZE(which), buf, &len, NULL, 0)) 420 return; 421 422 /* NULL specifies to use LC_C_LOCALE */ 423 if (3 != sscanf_l(buf, NULL, "%u.%u.%u", &major, &minor, &patch)) 424 return; 425 426 posix_spawn_can_use_setsid = (major >= 19); /* macOS Catalina */ 427 } 428 429 uv__spawn_init_posix_spawn(void)430 static void uv__spawn_init_posix_spawn(void) { 431 /* Init handles to all potentially non-defined functions */ 432 uv__spawn_init_posix_spawn_fncs(); 433 434 /* Init feature detection for POSIX_SPAWN_SETSID flag */ 435 uv__spawn_init_can_use_setsid(); 436 } 437 438 uv__spawn_set_posix_spawn_attrs(posix_spawnattr_t * attrs,const uv__posix_spawn_fncs_t * posix_spawn_fncs,const uv_process_options_t * options)439 static int uv__spawn_set_posix_spawn_attrs( 440 posix_spawnattr_t* attrs, 441 const uv__posix_spawn_fncs_t* posix_spawn_fncs, 442 const uv_process_options_t* options) { 443 int err; 444 unsigned int flags; 445 sigset_t signal_set; 446 447 err = posix_spawnattr_init(attrs); 448 if (err != 0) { 449 /* If initialization fails, no need to de-init, just return */ 450 return err; 451 } 452 453 if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { 454 /* kauth_cred_issuser currently requires exactly uid == 0 for these 455 * posixspawn_attrs (set_groups_np, setuid_np, setgid_np), which deviates 456 * from the normal specification of setuid (which also uses euid), and they 457 * are also undocumented syscalls, so we do not use them. */ 458 err = ENOSYS; 459 goto error; 460 } 461 462 /* Set flags for spawn behavior 463 * 1) POSIX_SPAWN_CLOEXEC_DEFAULT: (Apple Extension) All descriptors in the 464 * parent will be treated as if they had been created with O_CLOEXEC. The 465 * only fds that will be passed on to the child are those manipulated by 466 * the file actions 467 * 2) POSIX_SPAWN_SETSIGDEF: Signals mentioned in spawn-sigdefault in the 468 * spawn attributes will be reset to behave as their default 469 * 3) POSIX_SPAWN_SETSIGMASK: Signal mask will be set to the value of 470 * spawn-sigmask in attributes 471 * 4) POSIX_SPAWN_SETSID: Make the process a new session leader if a detached 472 * session was requested. */ 473 flags = POSIX_SPAWN_CLOEXEC_DEFAULT | 474 POSIX_SPAWN_SETSIGDEF | 475 POSIX_SPAWN_SETSIGMASK; 476 if (options->flags & UV_PROCESS_DETACHED) { 477 /* If running on a version of macOS where this flag is not supported, 478 * revert back to the fork/exec flow. Otherwise posix_spawn will 479 * silently ignore the flag. */ 480 if (!posix_spawn_can_use_setsid) { 481 err = ENOSYS; 482 goto error; 483 } 484 485 flags |= POSIX_SPAWN_SETSID; 486 } 487 err = posix_spawnattr_setflags(attrs, flags); 488 if (err != 0) 489 goto error; 490 491 /* Reset all signal the child to their default behavior */ 492 sigfillset(&signal_set); 493 err = posix_spawnattr_setsigdefault(attrs, &signal_set); 494 if (err != 0) 495 goto error; 496 497 /* Reset the signal mask for all signals */ 498 sigemptyset(&signal_set); 499 err = posix_spawnattr_setsigmask(attrs, &signal_set); 500 if (err != 0) 501 goto error; 502 503 return err; 504 505 error: 506 (void) posix_spawnattr_destroy(attrs); 507 return err; 508 } 509 510 uv__spawn_set_posix_spawn_file_actions(posix_spawn_file_actions_t * actions,const uv__posix_spawn_fncs_t * posix_spawn_fncs,const uv_process_options_t * options,int stdio_count,int (* pipes)[2])511 static int uv__spawn_set_posix_spawn_file_actions( 512 posix_spawn_file_actions_t* actions, 513 const uv__posix_spawn_fncs_t* posix_spawn_fncs, 514 const uv_process_options_t* options, 515 int stdio_count, 516 int (*pipes)[2]) { 517 int fd; 518 int fd2; 519 int use_fd; 520 int err; 521 522 err = posix_spawn_file_actions_init(actions); 523 if (err != 0) { 524 /* If initialization fails, no need to de-init, just return */ 525 return err; 526 } 527 528 /* Set the current working directory if requested */ 529 if (options->cwd != NULL) { 530 if (posix_spawn_fncs->file_actions.addchdir_np == NULL) { 531 err = ENOSYS; 532 goto error; 533 } 534 535 err = posix_spawn_fncs->file_actions.addchdir_np(actions, options->cwd); 536 if (err != 0) 537 goto error; 538 } 539 540 /* Do not return ENOSYS after this point, as we may mutate pipes. */ 541 542 /* First duplicate low numbered fds, since it's not safe to duplicate them, 543 * they could get replaced. Example: swapping stdout and stderr; without 544 * this fd 2 (stderr) would be duplicated into fd 1, thus making both 545 * stdout and stderr go to the same fd, which was not the intention. */ 546 for (fd = 0; fd < stdio_count; fd++) { 547 use_fd = pipes[fd][1]; 548 if (use_fd < 0 || use_fd >= fd) 549 continue; 550 use_fd = stdio_count; 551 for (fd2 = 0; fd2 < stdio_count; fd2++) { 552 /* If we were not setting POSIX_SPAWN_CLOEXEC_DEFAULT, we would need to 553 * also consider whether fcntl(fd, F_GETFD) returned without the 554 * FD_CLOEXEC flag set. */ 555 if (pipes[fd2][1] == use_fd) { 556 use_fd++; 557 fd2 = 0; 558 } 559 } 560 err = posix_spawn_file_actions_adddup2( 561 actions, 562 pipes[fd][1], 563 use_fd); 564 assert(err != ENOSYS); 565 if (err != 0) 566 goto error; 567 pipes[fd][1] = use_fd; 568 } 569 570 /* Second, move the descriptors into their respective places */ 571 for (fd = 0; fd < stdio_count; fd++) { 572 use_fd = pipes[fd][1]; 573 if (use_fd < 0) { 574 if (fd >= 3) 575 continue; 576 else { 577 /* If ignored, redirect to (or from) /dev/null, */ 578 err = posix_spawn_file_actions_addopen( 579 actions, 580 fd, 581 "/dev/null", 582 fd == 0 ? O_RDONLY : O_RDWR, 583 0); 584 assert(err != ENOSYS); 585 if (err != 0) 586 goto error; 587 continue; 588 } 589 } 590 591 if (fd == use_fd) 592 err = posix_spawn_file_actions_addinherit_np(actions, fd); 593 else 594 err = posix_spawn_file_actions_adddup2(actions, use_fd, fd); 595 assert(err != ENOSYS); 596 if (err != 0) 597 goto error; 598 599 /* Make sure the fd is marked as non-blocking (state shared between child 600 * and parent). */ 601 uv__nonblock_fcntl(use_fd, 0); 602 } 603 604 /* Finally, close all the superfluous descriptors */ 605 for (fd = 0; fd < stdio_count; fd++) { 606 use_fd = pipes[fd][1]; 607 if (use_fd < stdio_count) 608 continue; 609 610 /* Check if we already closed this. */ 611 for (fd2 = 0; fd2 < fd; fd2++) { 612 if (pipes[fd2][1] == use_fd) 613 break; 614 } 615 if (fd2 < fd) 616 continue; 617 618 err = posix_spawn_file_actions_addclose(actions, use_fd); 619 assert(err != ENOSYS); 620 if (err != 0) 621 goto error; 622 } 623 624 return 0; 625 626 error: 627 (void) posix_spawn_file_actions_destroy(actions); 628 return err; 629 } 630 uv__spawn_find_path_in_env(char ** env)631 char* uv__spawn_find_path_in_env(char** env) { 632 char** env_iterator; 633 const char path_var[] = "PATH="; 634 635 /* Look for an environment variable called PATH in the 636 * provided env array, and return its value if found */ 637 for (env_iterator = env; *env_iterator != NULL; env_iterator++) { 638 if (strncmp(*env_iterator, path_var, sizeof(path_var) - 1) == 0) { 639 /* Found "PATH=" at the beginning of the string */ 640 return *env_iterator + sizeof(path_var) - 1; 641 } 642 } 643 644 return NULL; 645 } 646 647 uv__spawn_resolve_and_spawn(const uv_process_options_t * options,posix_spawnattr_t * attrs,posix_spawn_file_actions_t * actions,pid_t * pid)648 static int uv__spawn_resolve_and_spawn(const uv_process_options_t* options, 649 posix_spawnattr_t* attrs, 650 posix_spawn_file_actions_t* actions, 651 pid_t* pid) { 652 const char *p; 653 const char *z; 654 const char *path; 655 size_t l; 656 size_t k; 657 int err; 658 int seen_eacces; 659 660 path = NULL; 661 err = -1; 662 seen_eacces = 0; 663 664 /* Short circuit for erroneous case */ 665 if (options->file == NULL) 666 return ENOENT; 667 668 /* The environment for the child process is that of the parent unless overriden 669 * by options->env */ 670 char** env = environ; 671 if (options->env != NULL) 672 env = options->env; 673 674 /* If options->file contains a slash, posix_spawn/posix_spawnp behave 675 * the same, and don't involve PATH resolution at all. Otherwise, if 676 * options->file does not include a slash, but no custom environment is 677 * to be used, the environment used for path resolution as well for the 678 * child process is that of the parent process, so posix_spawnp is the 679 * way to go. */ 680 if (strchr(options->file, '/') != NULL || options->env == NULL) { 681 do 682 err = posix_spawnp(pid, options->file, actions, attrs, options->args, env); 683 while (err == EINTR); 684 return err; 685 } 686 687 /* Look for the definition of PATH in the provided env */ 688 path = uv__spawn_find_path_in_env(options->env); 689 690 /* The following resolution logic (execvpe emulation) is copied from 691 * https://git.musl-libc.org/cgit/musl/tree/src/process/execvp.c 692 * and adapted to work for our specific usage */ 693 694 /* If no path was provided in options->env, use the default value 695 * to look for the executable */ 696 if (path == NULL) 697 path = _PATH_DEFPATH; 698 699 k = strnlen(options->file, NAME_MAX + 1); 700 if (k > NAME_MAX) 701 return ENAMETOOLONG; 702 703 l = strnlen(path, PATH_MAX - 1) + 1; 704 705 for (p = path;; p = z) { 706 /* Compose the new process file from the entry in the PATH 707 * environment variable and the actual file name */ 708 char b[PATH_MAX + NAME_MAX]; 709 z = strchr(p, ':'); 710 if (!z) 711 z = p + strlen(p); 712 if ((size_t)(z - p) >= l) { 713 if (!*z++) 714 break; 715 716 continue; 717 } 718 memcpy(b, p, z - p); 719 b[z - p] = '/'; 720 memcpy(b + (z - p) + (z > p), options->file, k + 1); 721 722 /* Try to spawn the new process file. If it fails with ENOENT, the 723 * new process file is not in this PATH entry, continue with the next 724 * PATH entry. */ 725 do 726 err = posix_spawn(pid, b, actions, attrs, options->args, env); 727 while (err == EINTR); 728 729 switch (err) { 730 case EACCES: 731 seen_eacces = 1; 732 break; /* continue search */ 733 case ENOENT: 734 case ENOTDIR: 735 break; /* continue search */ 736 default: 737 return err; 738 } 739 740 if (!*z++) 741 break; 742 } 743 744 if (seen_eacces) 745 return EACCES; 746 return err; 747 } 748 749 uv__spawn_and_init_child_posix_spawn(const uv_process_options_t * options,int stdio_count,int (* pipes)[2],pid_t * pid,const uv__posix_spawn_fncs_t * posix_spawn_fncs)750 static int uv__spawn_and_init_child_posix_spawn( 751 const uv_process_options_t* options, 752 int stdio_count, 753 int (*pipes)[2], 754 pid_t* pid, 755 const uv__posix_spawn_fncs_t* posix_spawn_fncs) { 756 int err; 757 posix_spawnattr_t attrs; 758 posix_spawn_file_actions_t actions; 759 760 err = uv__spawn_set_posix_spawn_attrs(&attrs, posix_spawn_fncs, options); 761 if (err != 0) 762 goto error; 763 764 /* This may mutate pipes. */ 765 err = uv__spawn_set_posix_spawn_file_actions(&actions, 766 posix_spawn_fncs, 767 options, 768 stdio_count, 769 pipes); 770 if (err != 0) { 771 (void) posix_spawnattr_destroy(&attrs); 772 goto error; 773 } 774 775 /* Try to spawn options->file resolving in the provided environment 776 * if any */ 777 err = uv__spawn_resolve_and_spawn(options, &attrs, &actions, pid); 778 assert(err != ENOSYS); 779 780 /* Destroy the actions/attributes */ 781 (void) posix_spawn_file_actions_destroy(&actions); 782 (void) posix_spawnattr_destroy(&attrs); 783 784 error: 785 /* In an error situation, the attributes and file actions are 786 * already destroyed, only the happy path requires cleanup */ 787 return UV__ERR(err); 788 } 789 #endif 790 uv__spawn_and_init_child_fork(const uv_process_options_t * options,int stdio_count,int (* pipes)[2],int error_fd,pid_t * pid)791 static int uv__spawn_and_init_child_fork(const uv_process_options_t* options, 792 int stdio_count, 793 int (*pipes)[2], 794 int error_fd, 795 pid_t* pid) { 796 sigset_t signewset; 797 sigset_t sigoldset; 798 799 /* Start the child with most signals blocked, to avoid any issues before we 800 * can reset them, but allow program failures to exit (and not hang). */ 801 sigfillset(&signewset); 802 sigdelset(&signewset, SIGKILL); 803 sigdelset(&signewset, SIGSTOP); 804 sigdelset(&signewset, SIGTRAP); 805 sigdelset(&signewset, SIGSEGV); 806 sigdelset(&signewset, SIGBUS); 807 sigdelset(&signewset, SIGILL); 808 sigdelset(&signewset, SIGSYS); 809 sigdelset(&signewset, SIGABRT); 810 if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0) 811 abort(); 812 813 *pid = fork(); 814 815 if (*pid == -1) { 816 /* Failed to fork */ 817 return UV__ERR(errno); 818 } 819 820 if (*pid == 0) { 821 /* Fork succeeded, in the child process */ 822 uv__process_child_init(options, stdio_count, pipes, error_fd); 823 abort(); 824 } 825 826 if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0) 827 abort(); 828 829 /* Fork succeeded, in the parent process */ 830 return 0; 831 } 832 uv__spawn_and_init_child(uv_loop_t * loop,const uv_process_options_t * options,int stdio_count,int (* pipes)[2],pid_t * pid)833 static int uv__spawn_and_init_child( 834 uv_loop_t* loop, 835 const uv_process_options_t* options, 836 int stdio_count, 837 int (*pipes)[2], 838 pid_t* pid) { 839 int signal_pipe[2] = { -1, -1 }; 840 int status; 841 int err; 842 int exec_errorno; 843 ssize_t r; 844 845 #if defined(__APPLE__) && !TARGET_OS_IPHONE 846 uv_once(&posix_spawn_init_once, uv__spawn_init_posix_spawn); 847 848 /* Special child process spawn case for macOS Big Sur (11.0) onwards 849 * 850 * Big Sur introduced a significant performance degradation on a call to 851 * fork/exec when the process has many pages mmaped in with MAP_JIT, like, say 852 * a javascript interpreter. Electron-based applications, for example, 853 * are impacted; though the magnitude of the impact depends on how much the 854 * app relies on subprocesses. 855 * 856 * On macOS, though, posix_spawn is implemented in a way that does not 857 * exhibit the problem. This block implements the forking and preparation 858 * logic with posix_spawn and its related primitives. It also takes advantage of 859 * the macOS extension POSIX_SPAWN_CLOEXEC_DEFAULT that makes impossible to 860 * leak descriptors to the child process. */ 861 err = uv__spawn_and_init_child_posix_spawn(options, 862 stdio_count, 863 pipes, 864 pid, 865 &posix_spawn_fncs); 866 867 /* The posix_spawn flow will return UV_ENOSYS if any of the posix_spawn_x_np 868 * non-standard functions is both _needed_ and _undefined_. In those cases, 869 * default back to the fork/execve strategy. For all other errors, just fail. */ 870 if (err != UV_ENOSYS) 871 return err; 872 873 #endif 874 875 /* This pipe is used by the parent to wait until 876 * the child has called `execve()`. We need this 877 * to avoid the following race condition: 878 * 879 * if ((pid = fork()) > 0) { 880 * kill(pid, SIGTERM); 881 * } 882 * else if (pid == 0) { 883 * execve("/bin/cat", argp, envp); 884 * } 885 * 886 * The parent sends a signal immediately after forking. 887 * Since the child may not have called `execve()` yet, 888 * there is no telling what process receives the signal, 889 * our fork or /bin/cat. 890 * 891 * To avoid ambiguity, we create a pipe with both ends 892 * marked close-on-exec. Then, after the call to `fork()`, 893 * the parent polls the read end until it EOFs or errors with EPIPE. 894 */ 895 err = uv__make_pipe(signal_pipe, 0); 896 if (err) 897 return err; 898 899 /* Acquire write lock to prevent opening new fds in worker threads */ 900 uv_rwlock_wrlock(&loop->cloexec_lock); 901 902 err = uv__spawn_and_init_child_fork(options, stdio_count, pipes, signal_pipe[1], pid); 903 904 /* Release lock in parent process */ 905 uv_rwlock_wrunlock(&loop->cloexec_lock); 906 907 uv__close(signal_pipe[1]); 908 909 if (err == 0) { 910 do 911 r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno)); 912 while (r == -1 && errno == EINTR); 913 914 if (r == 0) 915 ; /* okay, EOF */ 916 else if (r == sizeof(exec_errorno)) { 917 do 918 err = waitpid(*pid, &status, 0); /* okay, read errorno */ 919 while (err == -1 && errno == EINTR); 920 assert(err == *pid); 921 err = exec_errorno; 922 } else if (r == -1 && errno == EPIPE) { 923 /* Something unknown happened to our child before spawn */ 924 do 925 err = waitpid(*pid, &status, 0); /* okay, got EPIPE */ 926 while (err == -1 && errno == EINTR); 927 assert(err == *pid); 928 err = UV_EPIPE; 929 } else 930 abort(); 931 } 932 933 uv__close_nocheckstdio(signal_pipe[0]); 934 935 return err; 936 } 937 uv_spawn(uv_loop_t * loop,uv_process_t * process,const uv_process_options_t * options)938 int uv_spawn(uv_loop_t* loop, 939 uv_process_t* process, 940 const uv_process_options_t* options) { 941 #if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) 942 /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ 943 return UV_ENOSYS; 944 #else 945 int pipes_storage[8][2]; 946 int (*pipes)[2]; 947 int stdio_count; 948 pid_t pid; 949 int err; 950 int exec_errorno; 951 int i; 952 953 assert(options->file != NULL); 954 assert(!(options->flags & ~(UV_PROCESS_DETACHED | 955 UV_PROCESS_SETGID | 956 UV_PROCESS_SETUID | 957 UV_PROCESS_WINDOWS_HIDE | 958 UV_PROCESS_WINDOWS_HIDE_CONSOLE | 959 UV_PROCESS_WINDOWS_HIDE_GUI | 960 UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); 961 962 uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); 963 QUEUE_INIT(&process->queue); 964 process->status = 0; 965 966 stdio_count = options->stdio_count; 967 if (stdio_count < 3) 968 stdio_count = 3; 969 970 err = UV_ENOMEM; 971 pipes = pipes_storage; 972 if (stdio_count > (int) ARRAY_SIZE(pipes_storage)) 973 pipes = uv__malloc(stdio_count * sizeof(*pipes)); 974 975 if (pipes == NULL) 976 goto error; 977 978 for (i = 0; i < stdio_count; i++) { 979 pipes[i][0] = -1; 980 pipes[i][1] = -1; 981 } 982 983 for (i = 0; i < options->stdio_count; i++) { 984 err = uv__process_init_stdio(options->stdio + i, pipes[i]); 985 if (err) 986 goto error; 987 } 988 989 #ifdef UV_USE_SIGCHLD 990 uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); 991 #endif 992 993 /* Spawn the child */ 994 exec_errorno = uv__spawn_and_init_child(loop, options, stdio_count, pipes, &pid); 995 996 #if 0 997 /* This runs into a nodejs issue (it expects initialized streams, even if the 998 * exec failed). 999 * See https://github.com/libuv/libuv/pull/3107#issuecomment-782482608 */ 1000 if (exec_errorno != 0) 1001 goto error; 1002 #endif 1003 1004 /* Activate this handle if exec() happened successfully, even if we later 1005 * fail to open a stdio handle. This ensures we can eventually reap the child 1006 * with waitpid. */ 1007 if (exec_errorno == 0) { 1008 #ifndef UV_USE_SIGCHLD 1009 struct kevent event; 1010 EV_SET(&event, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, 0); 1011 if (kevent(loop->backend_fd, &event, 1, NULL, 0, NULL)) { 1012 if (errno != ESRCH) 1013 abort(); 1014 /* Process already exited. Call waitpid on the next loop iteration. */ 1015 process->flags |= UV_HANDLE_REAP; 1016 loop->flags |= UV_LOOP_REAP_CHILDREN; 1017 } 1018 #endif 1019 1020 process->pid = pid; 1021 process->exit_cb = options->exit_cb; 1022 QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue); 1023 uv__handle_start(process); 1024 } 1025 1026 for (i = 0; i < options->stdio_count; i++) { 1027 err = uv__process_open_stream(options->stdio + i, pipes[i]); 1028 if (err == 0) 1029 continue; 1030 1031 while (i--) 1032 uv__process_close_stream(options->stdio + i); 1033 1034 goto error; 1035 } 1036 1037 if (pipes != pipes_storage) 1038 uv__free(pipes); 1039 1040 return exec_errorno; 1041 1042 error: 1043 if (pipes != NULL) { 1044 for (i = 0; i < stdio_count; i++) { 1045 if (i < options->stdio_count) 1046 if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM)) 1047 continue; 1048 if (pipes[i][0] != -1) 1049 uv__close_nocheckstdio(pipes[i][0]); 1050 if (pipes[i][1] != -1) 1051 uv__close_nocheckstdio(pipes[i][1]); 1052 } 1053 1054 if (pipes != pipes_storage) 1055 uv__free(pipes); 1056 } 1057 1058 return err; 1059 #endif 1060 } 1061 1062 uv_process_kill(uv_process_t * process,int signum)1063 int uv_process_kill(uv_process_t* process, int signum) { 1064 return uv_kill(process->pid, signum); 1065 } 1066 1067 uv_kill(int pid,int signum)1068 int uv_kill(int pid, int signum) { 1069 if (kill(pid, signum)) 1070 return UV__ERR(errno); 1071 else 1072 return 0; 1073 } 1074 1075 uv__process_close(uv_process_t * handle)1076 void uv__process_close(uv_process_t* handle) { 1077 QUEUE_REMOVE(&handle->queue); 1078 uv__handle_stop(handle); 1079 if (QUEUE_EMPTY(&handle->loop->process_handles)) 1080 uv_signal_stop(&handle->loop->child_watcher); 1081 } 1082