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