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