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/mman.h>
32 #include <sys/procctl.h>
33 #include <sys/procdesc.h>
34 #include <sys/queue.h>
35 #include <sys/wait.h>
36
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <sched.h>
40 #include <spawn.h>
41 #include <signal.h>
42 #include <stdbool.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include "un-namespace.h"
47 #include "libc_private.h"
48
49 struct __posix_spawnattr {
50 short sa_flags;
51 pid_t sa_pgroup;
52 struct sched_param sa_schedparam;
53 int sa_schedpolicy;
54 sigset_t sa_sigdefault;
55 sigset_t sa_sigmask;
56 int sa_execfd;
57 int *sa_pdrfork_fdp;
58 int sa_pdflags;
59 };
60
61 struct __posix_spawn_file_actions {
62 STAILQ_HEAD(, __posix_spawn_file_actions_entry) fa_list;
63 };
64
65 typedef struct __posix_spawn_file_actions_entry {
66 STAILQ_ENTRY(__posix_spawn_file_actions_entry) fae_list;
67 enum {
68 FAE_OPEN,
69 FAE_DUP2,
70 FAE_CLOSE,
71 FAE_CHDIR,
72 FAE_FCHDIR,
73 FAE_CLOSEFROM,
74 } fae_action;
75
76 int fae_fildes;
77 union {
78 struct {
79 char *path;
80 #define fae_path fae_data.open.path
81 int oflag;
82 #define fae_oflag fae_data.open.oflag
83 mode_t mode;
84 #define fae_mode fae_data.open.mode
85 } open;
86 struct {
87 int newfildes;
88 #define fae_newfildes fae_data.dup2.newfildes
89 } dup2;
90 } fae_data;
91 } posix_spawn_file_actions_entry_t;
92
93 /*
94 * Spawn routines
95 */
96
97 static int
process_spawnattr(const posix_spawnattr_t sa)98 process_spawnattr(const posix_spawnattr_t sa)
99 {
100 struct sigaction sigact = { .sa_flags = 0, .sa_handler = SIG_DFL };
101 int aslr, i;
102
103 /*
104 * POSIX doesn't really describe in which order everything
105 * should be set. We'll just set them in the order in which they
106 * are mentioned.
107 */
108
109 /* Set process group */
110 if (sa->sa_flags & POSIX_SPAWN_SETPGROUP) {
111 if (setpgid(0, sa->sa_pgroup) != 0)
112 return (errno);
113 }
114
115 /* Set scheduler policy */
116 if (sa->sa_flags & POSIX_SPAWN_SETSCHEDULER) {
117 if (sched_setscheduler(0, sa->sa_schedpolicy,
118 &sa->sa_schedparam) != 0)
119 return (errno);
120 } else if (sa->sa_flags & POSIX_SPAWN_SETSCHEDPARAM) {
121 if (sched_setparam(0, &sa->sa_schedparam) != 0)
122 return (errno);
123 }
124
125 /* Reset user ID's */
126 if (sa->sa_flags & POSIX_SPAWN_RESETIDS) {
127 if (setegid(getgid()) != 0)
128 return (errno);
129 if (seteuid(getuid()) != 0)
130 return (errno);
131 }
132
133 /*
134 * Set signal masks/defaults.
135 * Use unwrapped syscall, libthr is in undefined state after vfork().
136 */
137 if (sa->sa_flags & POSIX_SPAWN_SETSIGMASK) {
138 __sys_sigprocmask(SIG_SETMASK, &sa->sa_sigmask, NULL);
139 }
140
141 if (sa->sa_flags & POSIX_SPAWN_SETSIGDEF) {
142 for (i = 1; i <= _SIG_MAXSIG; i++) {
143 if (sigismember(&sa->sa_sigdefault, i))
144 if (__sys_sigaction(i, &sigact, NULL) != 0)
145 return (errno);
146 }
147 }
148
149 /* Disable ASLR. */
150 if ((sa->sa_flags & POSIX_SPAWN_DISABLE_ASLR_NP) != 0) {
151 aslr = PROC_ASLR_FORCE_DISABLE;
152 if (procctl(P_PID, 0, PROC_ASLR_CTL, &aslr) != 0)
153 return (errno);
154 }
155
156 return (0);
157 }
158
159 static int
process_file_actions_entry(posix_spawn_file_actions_entry_t * fae)160 process_file_actions_entry(posix_spawn_file_actions_entry_t *fae)
161 {
162 int fd, saved_errno;
163
164 switch (fae->fae_action) {
165 case FAE_OPEN:
166 /* Perform an open(), make it use the right fd */
167 fd = _open(fae->fae_path, fae->fae_oflag, fae->fae_mode);
168 if (fd < 0)
169 return (errno);
170 if (fd != fae->fae_fildes) {
171 if (_dup2(fd, fae->fae_fildes) == -1) {
172 saved_errno = errno;
173 (void)_close(fd);
174 return (saved_errno);
175 }
176 if (_close(fd) != 0) {
177 if (errno == EBADF)
178 return (EBADF);
179 }
180 }
181 if (_fcntl(fae->fae_fildes, F_SETFD, 0) == -1)
182 return (errno);
183 break;
184 case FAE_DUP2:
185 /* Perform a dup2() */
186 if (_dup2(fae->fae_fildes, fae->fae_newfildes) == -1)
187 return (errno);
188 if (_fcntl(fae->fae_newfildes, F_SETFD, 0) == -1)
189 return (errno);
190 break;
191 case FAE_CLOSE:
192 /* Perform a close(), do not fail if already closed */
193 (void)_close(fae->fae_fildes);
194 break;
195 case FAE_CHDIR:
196 if (chdir(fae->fae_path) != 0)
197 return (errno);
198 break;
199 case FAE_FCHDIR:
200 if (fchdir(fae->fae_fildes) != 0)
201 return (errno);
202 break;
203 case FAE_CLOSEFROM:
204 closefrom(fae->fae_fildes);
205 break;
206 }
207 return (0);
208 }
209
210 static int
process_file_actions(const posix_spawn_file_actions_t fa)211 process_file_actions(const posix_spawn_file_actions_t fa)
212 {
213 posix_spawn_file_actions_entry_t *fae;
214 int error;
215
216 /* Replay all file descriptor modifications */
217 STAILQ_FOREACH(fae, &fa->fa_list, fae_list) {
218 error = process_file_actions_entry(fae);
219 if (error)
220 return (error);
221 }
222 return (0);
223 }
224
225 struct posix_spawn_args {
226 const char *path;
227 const posix_spawn_file_actions_t *fa;
228 const posix_spawnattr_t *sa;
229 char * const * argv;
230 char * const * envp;
231 int use_env_path;
232 volatile int error;
233 };
234
235 #define _RFORK_THREAD_STACK_SIZE 4096
236
237 static int
_posix_spawn_thr(void * data)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->sa != NULL && (*(psa->sa))->sa_execfd != -1)
256 fexecve((*(psa->sa))->sa_execfd, psa->argv, envp);
257 else if (psa->use_env_path)
258 __libc_execvpe(psa->path, psa->argv, envp);
259 else
260 _execve(psa->path, psa->argv, envp);
261 psa->error = errno;
262
263 /* This is called in such a way that it must not exit. */
264 _exit(127);
265 }
266
267 static int
do_posix_spawn(pid_t * pid,const char * path,const posix_spawn_file_actions_t * fa,const posix_spawnattr_t * sa,char * const argv[],char * const envp[],bool use_env_path)268 do_posix_spawn(pid_t *pid, const char *path,
269 const posix_spawn_file_actions_t *fa,
270 const posix_spawnattr_t *sa,
271 char * const argv[], char * const envp[], bool use_env_path)
272 {
273 struct posix_spawn_args psa;
274 pid_t p;
275 int pfd;
276 bool do_pfd;
277 char *guard, *stack;
278 size_t stacksz, pagesz;
279
280 #if defined(__i386__) || defined(__amd64__)
281 stacksz = _RFORK_THREAD_STACK_SIZE;
282 pagesz = getpagesize();
283
284 if (use_env_path) {
285 size_t cnt;
286
287 /*
288 * We need to make sure we have enough room on the stack for the
289 * potential alloca() in execvPe if it gets kicked back an
290 * ENOEXEC from execve(2), plus the original buffer we gave
291 * ourselves; this protects us in the event that the caller
292 * intentionally or inadvertently supplies enough arguments to
293 * make us blow past the stack we've allocated from it.
294 */
295 for (cnt = 0; argv[cnt] != NULL; ++cnt)
296 ;
297 stacksz += MAX(3, cnt + 2) * sizeof(char *);
298 }
299
300 stacksz = round_page(stacksz);
301 guard = mmap(NULL, stacksz + pagesz, 0, MAP_GUARD, -1, 0);
302 if (guard == MAP_FAILED)
303 return (ENOMEM);
304 stack = mmap(guard + pagesz, stacksz, PROT_READ | PROT_WRITE,
305 MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0);
306 if (stack == MAP_FAILED) {
307 munmap(guard, stacksz + pagesz);
308 return (ENOMEM);
309 }
310 #else
311 guard = stack = NULL;
312 pagesz = stacksz = 0;
313 #endif
314 psa.path = path;
315 psa.fa = fa;
316 psa.sa = sa;
317 psa.argv = argv;
318 psa.envp = envp;
319 psa.use_env_path = use_env_path;
320 psa.error = 0;
321
322 do_pfd = sa != NULL && (*sa)->sa_pdrfork_fdp != NULL;
323
324 /*
325 * Passing RFSPAWN to rfork(2) gives us effectively a vfork that drops
326 * non-ignored signal handlers. We'll fall back to the slightly less
327 * ideal vfork(2) if we get an EINVAL from rfork -- this should only
328 * happen with newer libc on older kernel that doesn't accept
329 * RFSPAWN.
330 *
331 * Combination of vfork() (or its equivalent rfork() form) and
332 * a special property of the libthr rtld locks ensure that
333 * rtld is operational in the child. In particular, libthr
334 * rtld locks do not store owner' tid into the lock word.
335 *
336 * x86 stores the return address on the stack, so rfork(2)
337 * cannot work as-is because the child would clobber the
338 * return address of the parent. Because of this, we must use
339 * rfork_thread instead.
340 *
341 * Every other architecture stores the return address in a
342 * register, the trivial rfork_thread() wrapper is provided
343 * for them. The only minor drawback is that the stack is
344 * temporarily allocated.
345 */
346 if (do_pfd) {
347 p = pdrfork_thread(&pfd, PD_CLOEXEC | (*sa)->sa_pdflags,
348 RFSPAWN, stack + stacksz, _posix_spawn_thr, &psa);
349 } else {
350 p = rfork_thread(RFSPAWN, stack + stacksz, _posix_spawn_thr,
351 &psa);
352 }
353 if (stack != NULL)
354 munmap(guard, stacksz + pagesz);
355
356 /*
357 * The above block should leave us in a state where we've either
358 * succeeded and we're ready to process the results, or we need to
359 * fallback to vfork() if the kernel didn't like RFSPAWN.
360 */
361
362 if (p == -1 && errno == EINVAL) {
363 if (do_pfd)
364 return (EOPNOTSUPP);
365 p = vfork();
366 if (p == 0)
367 /* _posix_spawn_thr does not return */
368 _posix_spawn_thr(&psa);
369 }
370 if (p == -1)
371 return (errno);
372 if (psa.error != 0) {
373 /* Failed; ready to reap */
374 if (do_pfd)
375 (void)_close(pfd);
376 else
377 _waitpid(p, NULL, WNOHANG);
378 } else if (pid != NULL) {
379 /* exec succeeded */
380 *pid = p;
381 if (do_pfd)
382 *((*sa)->sa_pdrfork_fdp) = pfd;
383 }
384 return (psa.error);
385 }
386
387 int
posix_spawn(pid_t * pid,const char * path,const posix_spawn_file_actions_t * fa,const posix_spawnattr_t * sa,char * const argv[],char * const envp[])388 posix_spawn(pid_t *pid, const char *path,
389 const posix_spawn_file_actions_t *fa,
390 const posix_spawnattr_t *sa,
391 char * const argv[], char * const envp[])
392 {
393 return (do_posix_spawn(pid, path, fa, sa, argv, envp, false));
394 }
395
396 int
posix_spawnp(pid_t * pid,const char * path,const posix_spawn_file_actions_t * fa,const posix_spawnattr_t * sa,char * const argv[],char * const envp[])397 posix_spawnp(pid_t *pid, const char *path,
398 const posix_spawn_file_actions_t *fa,
399 const posix_spawnattr_t *sa,
400 char * const argv[], char * const envp[])
401 {
402 return (do_posix_spawn(pid, path, fa, sa, argv, envp, true));
403 }
404
405 /*
406 * File descriptor actions
407 */
408
409 int
posix_spawn_file_actions_init(posix_spawn_file_actions_t * ret)410 posix_spawn_file_actions_init(posix_spawn_file_actions_t *ret)
411 {
412 posix_spawn_file_actions_t fa;
413
414 fa = malloc(sizeof(struct __posix_spawn_file_actions));
415 if (fa == NULL)
416 return (errno);
417
418 STAILQ_INIT(&fa->fa_list);
419 *ret = fa;
420 return (0);
421 }
422
423 int
posix_spawn_file_actions_destroy(posix_spawn_file_actions_t * fa)424 posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *fa)
425 {
426 posix_spawn_file_actions_entry_t *fae;
427
428 while ((fae = STAILQ_FIRST(&(*fa)->fa_list)) != NULL) {
429 /* Remove file action entry from the queue */
430 STAILQ_REMOVE_HEAD(&(*fa)->fa_list, fae_list);
431
432 /* Deallocate file action entry */
433 if (fae->fae_action == FAE_OPEN ||
434 fae->fae_action == FAE_CHDIR)
435 free(fae->fae_path);
436 free(fae);
437 }
438
439 free(*fa);
440 return (0);
441 }
442
443 int
posix_spawn_file_actions_addopen(posix_spawn_file_actions_t * __restrict fa,int fildes,const char * __restrict path,int oflag,mode_t mode)444 posix_spawn_file_actions_addopen(posix_spawn_file_actions_t * __restrict fa,
445 int fildes, const char * __restrict path, int oflag, mode_t mode)
446 {
447 posix_spawn_file_actions_entry_t *fae;
448 int error;
449
450 if (fildes < 0)
451 return (EBADF);
452
453 /* Allocate object */
454 fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
455 if (fae == NULL)
456 return (errno);
457
458 /* Set values and store in queue */
459 fae->fae_action = FAE_OPEN;
460 fae->fae_path = strdup(path);
461 if (fae->fae_path == NULL) {
462 error = errno;
463 free(fae);
464 return (error);
465 }
466 fae->fae_fildes = fildes;
467 fae->fae_oflag = oflag;
468 fae->fae_mode = mode;
469
470 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
471 return (0);
472 }
473
474 int
posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t * fa,int fildes,int newfildes)475 posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *fa,
476 int fildes, int newfildes)
477 {
478 posix_spawn_file_actions_entry_t *fae;
479
480 if (fildes < 0 || newfildes < 0)
481 return (EBADF);
482
483 /* Allocate object */
484 fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
485 if (fae == NULL)
486 return (errno);
487
488 /* Set values and store in queue */
489 fae->fae_action = FAE_DUP2;
490 fae->fae_fildes = fildes;
491 fae->fae_newfildes = newfildes;
492
493 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
494 return (0);
495 }
496
497 int
posix_spawn_file_actions_addclose(posix_spawn_file_actions_t * fa,int fildes)498 posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *fa,
499 int fildes)
500 {
501 posix_spawn_file_actions_entry_t *fae;
502
503 if (fildes < 0)
504 return (EBADF);
505
506 /* Allocate object */
507 fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
508 if (fae == NULL)
509 return (errno);
510
511 /* Set values and store in queue */
512 fae->fae_action = FAE_CLOSE;
513 fae->fae_fildes = fildes;
514
515 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
516 return (0);
517 }
518
519 int
posix_spawn_file_actions_addchdir_np(posix_spawn_file_actions_t * __restrict fa,const char * __restrict path)520 posix_spawn_file_actions_addchdir_np(posix_spawn_file_actions_t *
521 __restrict fa, const char *__restrict path)
522 {
523 posix_spawn_file_actions_entry_t *fae;
524 int error;
525
526 fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
527 if (fae == NULL)
528 return (errno);
529
530 fae->fae_action = FAE_CHDIR;
531 fae->fae_path = strdup(path);
532 if (fae->fae_path == NULL) {
533 error = errno;
534 free(fae);
535 return (error);
536 }
537
538 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
539 return (0);
540 }
541 __weak_reference(posix_spawn_file_actions_addchdir_np,
542 posix_spawn_file_actions_addchdir);
543
544 int
posix_spawn_file_actions_addfchdir_np(posix_spawn_file_actions_t * __restrict fa,int fildes)545 posix_spawn_file_actions_addfchdir_np(posix_spawn_file_actions_t *__restrict fa,
546 int fildes)
547 {
548 posix_spawn_file_actions_entry_t *fae;
549
550 if (fildes < 0)
551 return (EBADF);
552
553 /* Allocate object */
554 fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
555 if (fae == NULL)
556 return (errno);
557
558 fae->fae_action = FAE_FCHDIR;
559 fae->fae_fildes = fildes;
560
561 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
562 return (0);
563 }
564
565 __weak_reference(posix_spawn_file_actions_addfchdir_np,
566 posix_spawn_file_actions_addfchdir);
567
568 int
posix_spawn_file_actions_addclosefrom_np(posix_spawn_file_actions_t * __restrict fa,int from)569 posix_spawn_file_actions_addclosefrom_np (posix_spawn_file_actions_t *
570 __restrict fa, int from)
571 {
572 posix_spawn_file_actions_entry_t *fae;
573
574 if (from < 0)
575 return (EBADF);
576
577 /* Allocate object */
578 fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
579 if (fae == NULL)
580 return (errno);
581
582 fae->fae_action = FAE_CLOSEFROM;
583 fae->fae_fildes = from;
584
585 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
586 return (0);
587 }
588
589 /*
590 * Spawn attributes
591 */
592
593 int
posix_spawnattr_init(posix_spawnattr_t * ret)594 posix_spawnattr_init(posix_spawnattr_t *ret)
595 {
596 posix_spawnattr_t sa;
597
598 sa = calloc(1, sizeof(struct __posix_spawnattr));
599 if (sa == NULL)
600 return (errno);
601 sa->sa_execfd = -1;
602
603 /* Set defaults as specified by POSIX, cleared above */
604 *ret = sa;
605 return (0);
606 }
607
608 int
posix_spawnattr_destroy(posix_spawnattr_t * sa)609 posix_spawnattr_destroy(posix_spawnattr_t *sa)
610 {
611 free(*sa);
612 return (0);
613 }
614
615 int
posix_spawnattr_getflags(const posix_spawnattr_t * __restrict sa,short * __restrict flags)616 posix_spawnattr_getflags(const posix_spawnattr_t * __restrict sa,
617 short * __restrict flags)
618 {
619 *flags = (*sa)->sa_flags;
620 return (0);
621 }
622
623 int
posix_spawnattr_getpgroup(const posix_spawnattr_t * __restrict sa,pid_t * __restrict pgroup)624 posix_spawnattr_getpgroup(const posix_spawnattr_t * __restrict sa,
625 pid_t * __restrict pgroup)
626 {
627 *pgroup = (*sa)->sa_pgroup;
628 return (0);
629 }
630
631 int
posix_spawnattr_getschedparam(const posix_spawnattr_t * __restrict sa,struct sched_param * __restrict schedparam)632 posix_spawnattr_getschedparam(const posix_spawnattr_t * __restrict sa,
633 struct sched_param * __restrict schedparam)
634 {
635 *schedparam = (*sa)->sa_schedparam;
636 return (0);
637 }
638
639 int
posix_spawnattr_getschedpolicy(const posix_spawnattr_t * __restrict sa,int * __restrict schedpolicy)640 posix_spawnattr_getschedpolicy(const posix_spawnattr_t * __restrict sa,
641 int * __restrict schedpolicy)
642 {
643 *schedpolicy = (*sa)->sa_schedpolicy;
644 return (0);
645 }
646
647 int
posix_spawnattr_getsigdefault(const posix_spawnattr_t * __restrict sa,sigset_t * __restrict sigdefault)648 posix_spawnattr_getsigdefault(const posix_spawnattr_t * __restrict sa,
649 sigset_t * __restrict sigdefault)
650 {
651 *sigdefault = (*sa)->sa_sigdefault;
652 return (0);
653 }
654
655 int
posix_spawnattr_getsigmask(const posix_spawnattr_t * __restrict sa,sigset_t * __restrict sigmask)656 posix_spawnattr_getsigmask(const posix_spawnattr_t * __restrict sa,
657 sigset_t * __restrict sigmask)
658 {
659 *sigmask = (*sa)->sa_sigmask;
660 return (0);
661 }
662
663 int
posix_spawnattr_getexecfd_np(const posix_spawnattr_t * __restrict sa,int * __restrict fdp)664 posix_spawnattr_getexecfd_np(const posix_spawnattr_t * __restrict sa,
665 int * __restrict fdp)
666 {
667 *fdp = (*sa)->sa_execfd;
668 return (0);
669 }
670
671 int
posix_spawnattr_getprocdescp_np(const posix_spawnattr_t * __restrict sa,int ** __restrict fdpp,int * __restrict pdrflagsp)672 posix_spawnattr_getprocdescp_np(const posix_spawnattr_t * __restrict sa,
673 int ** __restrict fdpp, int * __restrict pdrflagsp)
674 {
675 *fdpp = (*sa)->sa_pdrfork_fdp;
676 *pdrflagsp = (*sa)->sa_pdflags;
677 return (0);
678 }
679
680 int
posix_spawnattr_setflags(posix_spawnattr_t * sa,short flags)681 posix_spawnattr_setflags(posix_spawnattr_t *sa, short flags)
682 {
683 if ((flags & ~(POSIX_SPAWN_RESETIDS | POSIX_SPAWN_SETPGROUP |
684 POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER |
685 POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK |
686 POSIX_SPAWN_DISABLE_ASLR_NP)) != 0)
687 return (EINVAL);
688 (*sa)->sa_flags = flags;
689 return (0);
690 }
691
692 int
posix_spawnattr_setpgroup(posix_spawnattr_t * sa,pid_t pgroup)693 posix_spawnattr_setpgroup(posix_spawnattr_t *sa, pid_t pgroup)
694 {
695 (*sa)->sa_pgroup = pgroup;
696 return (0);
697 }
698
699 int
posix_spawnattr_setschedparam(posix_spawnattr_t * __restrict sa,const struct sched_param * __restrict schedparam)700 posix_spawnattr_setschedparam(posix_spawnattr_t * __restrict sa,
701 const struct sched_param * __restrict schedparam)
702 {
703 (*sa)->sa_schedparam = *schedparam;
704 return (0);
705 }
706
707 int
posix_spawnattr_setschedpolicy(posix_spawnattr_t * sa,int schedpolicy)708 posix_spawnattr_setschedpolicy(posix_spawnattr_t *sa, int schedpolicy)
709 {
710 (*sa)->sa_schedpolicy = schedpolicy;
711 return (0);
712 }
713
714 int
posix_spawnattr_setsigdefault(posix_spawnattr_t * __restrict sa,const sigset_t * __restrict sigdefault)715 posix_spawnattr_setsigdefault(posix_spawnattr_t * __restrict sa,
716 const sigset_t * __restrict sigdefault)
717 {
718 (*sa)->sa_sigdefault = *sigdefault;
719 return (0);
720 }
721
722 int
posix_spawnattr_setsigmask(posix_spawnattr_t * __restrict sa,const sigset_t * __restrict sigmask)723 posix_spawnattr_setsigmask(posix_spawnattr_t * __restrict sa,
724 const sigset_t * __restrict sigmask)
725 {
726 (*sa)->sa_sigmask = *sigmask;
727 return (0);
728 }
729
730 int
posix_spawnattr_setexecfd_np(posix_spawnattr_t * __restrict sa,int execfd)731 posix_spawnattr_setexecfd_np(posix_spawnattr_t * __restrict sa,
732 int execfd)
733 {
734 (*sa)->sa_execfd = execfd;
735 return (0);
736 }
737
738 int
posix_spawnattr_setprocdescp_np(const posix_spawnattr_t * __restrict sa,int * __restrict fdp,int pdrflags)739 posix_spawnattr_setprocdescp_np(const posix_spawnattr_t * __restrict sa,
740 int * __restrict fdp, int pdrflags)
741 {
742 (*sa)->sa_pdrfork_fdp = fdp;
743 (*sa)->sa_pdflags = pdrflags;
744 return (0);
745 }
746