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