]> git.saurik.com Git - apple/xnu.git/blame - libsyscall/wrappers/spawn/posix_spawn.c
xnu-4570.71.2.tar.gz
[apple/xnu.git] / libsyscall / wrappers / spawn / posix_spawn.c
CommitLineData
39236c6e
A
1/*
2 * Copyright (c) 2006-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * [SPN] Support for _POSIX_SPAWN
26 */
27
28#define CONFIG_MEMORYSTATUS 1 // <rdar://problem/13604997>
29#include <sys/types.h> /* for user_size_t */
30#include <spawn.h>
31#include <spawn_private.h>
32#include <sys/spawn_internal.h>
33#include <sys/process_policy.h>
34#include <stdlib.h>
35#include <errno.h>
36#include <limits.h> /* for OPEN_MAX, PATH_MAX */
37#include <string.h>
38#include <strings.h>
39#include <mach/port.h>
40#include <mach/exception_types.h>
3e170ce0 41#include <mach/coalition.h> /* for COALITION_TYPE_MAX */
39037602 42#include <sys/kern_memorystatus.h>
39236c6e
A
43
44/*
45 * posix_spawnattr_init
46 *
47 * Description: Initialize a spawn attributes object attr with default values
48 *
49 * Parameters: attr The spawn attributes object to be
50 * initialized
51 *
52 * Returns: 0 Success
53 * ENOMEM Insufficient memory exists to
54 * initialize the spawn attributes object.
55 *
56 * Note: As an implementation detail, the externally visibily type
57 * posix_spawnattr_t is defined to be a void *, and initialization
58 * involves allocation of a memory object. Subsequent changes to
59 * the spawn attributes may result in reallocation under the
60 * covers.
61 *
62 * Reinitialization of an already initialized spawn attributes
63 * object will result in memory being leaked. Because spawn
64 * attributes are not required to be used in conjunction with a
65 * static initializer, there is no way to distinguish a spawn
66 * attribute with stack garbage from one that's been initialized.
67 * This is arguably an API design error.
68 */
69int
70posix_spawnattr_init(posix_spawnattr_t *attr)
71{
72 _posix_spawnattr_t *psattrp = (_posix_spawnattr_t *)attr;
73 int err = 0;
74
75 if ((*psattrp = (_posix_spawnattr_t)malloc(sizeof(struct _posix_spawnattr))) == NULL) {
76 err = ENOMEM;
77 } else {
78
79 /*
80 * The default value of this attribute shall be as if no
81 * flags were set
82 */
83 (*psattrp)->psa_flags = 0;
84
85 /*
86 * The default value of this attribute shall be an empty
87 * signal set
88 */
89 (*psattrp)->psa_sigdefault = 0;
90
91 /* The default value of this attribute is unspecified */
92 (*psattrp)->psa_sigmask = 0;
93
94 /* The default value of this attribute shall be zero */
95 (*psattrp)->psa_pgroup = 0; /* doesn't matter */
96
97 /* Default is no binary preferences, i.e. use normal grading */
98 memset((*psattrp)->psa_binprefs, 0,
99 sizeof((*psattrp)->psa_binprefs));
100
101 /* Default is no port actions to take */
102 (*psattrp)->psa_ports = NULL;
103
104 /*
105 * The default value of this attribute shall be an no
106 * process control on resource starvation
107 */
108 (*psattrp)->psa_pcontrol = 0;
109
110 /*
111 * Initializing the alignment paddings.
112 */
113
114 (*psattrp)->short_padding = 0;
115 (*psattrp)->flags_padding = 0;
39236c6e 116
fe8ab488
A
117 /* Default is no new apptype requested */
118 (*psattrp)->psa_apptype = POSIX_SPAWN_PROCESS_TYPE_DEFAULT;
39236c6e
A
119
120 /* Jetsam related */
121 (*psattrp)->psa_jetsam_flags = 0;
122 (*psattrp)->psa_priority = -1;
3e170ce0
A
123 (*psattrp)->psa_memlimit_active = -1;
124 (*psattrp)->psa_memlimit_inactive = -1;
39236c6e
A
125
126 /* Default is no CPU usage monitor active. */
127 (*psattrp)->psa_cpumonitor_percent = 0;
128 (*psattrp)->psa_cpumonitor_interval = 0;
129
130 /* Default is no MAC policy extensions. */
131 (*psattrp)->psa_mac_extensions = NULL;
fe8ab488 132
3e170ce0
A
133 /* Default is to inherit parent's coalition(s) */
134 (*psattrp)->psa_coalition_info = NULL;
135
490019cf 136 (*psattrp)->psa_persona_info = NULL;
3e170ce0
A
137
138 /*
139 * old coalition field
140 * For backwards compatibility reasons, we set this to 1
141 * which is the first valid coalition id. This will allow
142 * newer user space code to properly spawn processes on
143 * older kernels
144 * (they will just all end up in the same coalition).
145 */
146 (*psattrp)->psa_reserved = 1;
fe8ab488
A
147
148 /* Default is no new clamp */
149 (*psattrp)->psa_qos_clamp = POSIX_SPAWN_PROC_CLAMP_NONE;
3e170ce0
A
150
151 /* Default is no change to role */
152 (*psattrp)->psa_darwin_role = POSIX_SPAWN_DARWIN_ROLE_NONE;
39236c6e
A
153 }
154
155 return (err);
156}
157
158
159/*
160 * posix_spawnattr_destroy
161 *
162 * Description: Destroy a spawn attributes object that was previously
163 * initialized via posix_spawnattr_init() by freeing any
164 * memory associated with it and setting it to an invalid value.
165 *
166 * Parameters: attr The spawn attributes object to be
167 * destroyed.
168 *
169 * Returns: 0 Success
170 *
171 * Notes: The destroyed spawn attribute results in the void * pointer
172 * being set to NULL; subsequent use without reinitialization
173 * will result in explicit program failure (rather than merely
174 * "undefined behaviour").
175 *
176 * NOTIMP: Allowed failures (checking NOT required):
177 * EINVAL The value specified by attr is invalid.
178 */
179static int posix_spawn_destroyportactions_np(posix_spawnattr_t *);
3e170ce0 180static int posix_spawn_destroycoalition_info_np(posix_spawnattr_t *);
490019cf 181static int posix_spawn_destroypersona_info_np(posix_spawnattr_t *);
39236c6e
A
182
183int
184posix_spawnattr_destroy(posix_spawnattr_t *attr)
185{
186 _posix_spawnattr_t psattr;
187
188 if (attr == NULL || *attr == NULL)
189 return EINVAL;
190
191 psattr = *(_posix_spawnattr_t *)attr;
192 posix_spawn_destroyportactions_np(attr);
3e170ce0 193 posix_spawn_destroycoalition_info_np(attr);
490019cf 194 posix_spawn_destroypersona_info_np(attr);
39236c6e
A
195
196 free(psattr);
197 *attr = NULL;
198
199 return (0);
200}
201
202
203/*
204 * posix_spawnattr_setflags
205 *
206 * Description: Set the spawn flags attribute for the spawn attribute object
207 * referred to by 'attr'.
208 *
209 * Parameters: attr The spawn attributes object whose flags
210 * are to be set
211 * flags The flags value to set
212 *
213 * Returns: 0 Success
214 *
215 * NOTIMP: Allowed failures (checking NOT required):
216 * EINVAL The value specified by attr is invalid.
217 * EINVAL The value of the attribute being set is not valid.
218 */
219int
220posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags)
221{
222 _posix_spawnattr_t psattr;
223
224 if (attr == NULL || *attr == NULL)
225 return EINVAL;
226
227 psattr = *(_posix_spawnattr_t *)attr;
228 psattr->psa_flags = flags;
229
230 return (0);
231}
232
233
234/*
235 * posix_spawnattr_getflags
236 *
237 * Description: Retrieve the spawn attributes flag for the spawn attributes
238 * object referenced by 'attr' and place them in the memory
239 * location referenced by 'flagsp'
240 *
241 * Parameters: attr The spawn attributes object whose flags
242 * are to be retrieved
243 * flagsp A pointer to a short value to receive
244 * the flags
245 *
246 * Returns: 0 Success
247 *
248 * Implicit Returns:
249 * *flagps (modified) The flags value from the spawn
250 * attributes object
251 *
252 * NOTIMP: Allowed failures (checking NOT required):
253 * EINVAL The value specified by attr is invalid.
254 * EINVAL The value of the attribute being set is not valid.
255 */
256int
257posix_spawnattr_getflags(const posix_spawnattr_t * __restrict attr,
258 short * __restrict flagsp)
259{
260 _posix_spawnattr_t psattr;
261
262 if (attr == NULL || *attr == NULL)
263 return EINVAL;
264
265 psattr = *(_posix_spawnattr_t *)attr;
266 *flagsp = psattr->psa_flags;
267
268 return (0);
269}
270
271
272/*
273 * posix_spawnattr_getsigdefault
274 *
275 * Description: Retrieve the set of signals to be set to default according to
276 * the spawn attribute value referenced by 'attr' and place the
277 * result into the memory containing the sigset_t referenced by
278 * 'sigdefault'
279 *
280 * Parameters: attr The spawn attributes object whose
281 * signal set for default signals is to
282 * be retrieved
283 * sigdefault A pointer to the sigset_t to receive
284 * the signal set
285 *
286 * Returns: 0 Success
287 *
288 * Implicit Returns:
289 * *sigdefault (modified) The signal set of signals to default
290 * from the spawn attributes object
291 */
292int
293posix_spawnattr_getsigdefault(const posix_spawnattr_t * __restrict attr,
294 sigset_t * __restrict sigdefault)
295{
296 _posix_spawnattr_t psattr;
297
298 if (attr == NULL || *attr == NULL)
299 return EINVAL;
300
301 psattr = *(_posix_spawnattr_t *)attr;
302 *sigdefault = psattr->psa_sigdefault;
303
304 return (0);
305}
306
307
308/*
309 * posix_spawnattr_getpgroup
310 *
311 * Description: Obtain the value of the spawn process group attribute from the
312 * spawn attributes object referenced by 'attr' and place the
313 * results in the memory location referenced by 'pgroup'
314 *
315 * Parameters: attr The spawn attributes object whose
316 * process group information is to be
317 * retrieved
318 * pgroup A pointer to the pid_t to receive the
319 * process group
320 *
321 * Returns: 0 Success
322 *
323 * Implicit Returns:
324 * *pgroup (modified) The process group information from the
325 * spawn attributes object
326 */
327int
328posix_spawnattr_getpgroup(const posix_spawnattr_t * __restrict attr,
329 pid_t * __restrict pgroup)
330{
331 _posix_spawnattr_t psattr;
332
333 if (attr == NULL || *attr == NULL)
334 return EINVAL;
335
336 psattr = *(_posix_spawnattr_t *)attr;
337 *pgroup = psattr->psa_pgroup;
338
339 return (0);
340}
341
342
343/*
344 * posix_spawnattr_getsigmask
345 *
346 * Description: Obtain the value of the spawn signal mask attribute from the
347 * spawn attributes object referenced by 'attr' and place the
348 * result into the memory containing the sigset_t referenced by
349 * 'sigmask'
350 *
351 * Parameters: attr The spawn attributes object whose
352 * signal set for masked signals is to
353 * be retrieved
354 * sigmask A pointer to the sigset_t to receive
355 * the signal set
356 *
357 * Returns: 0 Success
358 *
359 * Implicit Returns:
360 * *sigmask (modified) The signal set of signals to mask
361 * from the spawn attributes object
362 */
363int
364posix_spawnattr_getsigmask(const posix_spawnattr_t * __restrict attr,
365 sigset_t * __restrict sigmask)
366{
367 _posix_spawnattr_t psattr;
368
369 if (attr == NULL || *attr == NULL)
370 return EINVAL;
371
372 psattr = *(_posix_spawnattr_t *)attr;
373 *sigmask = psattr->psa_sigmask;
374
375 return (0);
376}
377
378/*
379 * posix_spawnattr_getbinpref_np
380 *
381 * Description: Obtain the value of the spawn binary preferences attribute from
382 * the spawn attributes object referenced by 'attr' and place the
383 * result into the memory referenced by 'pref'.
384 *
385 * Parameters: attr The spawn attributes object whose
386 * binary preferences are to be retrieved
387 * count The size of the cpu_type_t array
388 * pref An array of cpu types
389 * ocount The actual number copied
390 *
391 * Returns: 0 No binary preferences found
392 * > 0 The number of cpu types (less than
393 * count) copied over from 'attr'.
394 *
395 * Implicit Returns:
396 * *pref (modified) The binary preferences array
397 * from the spawn attributes object
398 */
399int
400posix_spawnattr_getbinpref_np(const posix_spawnattr_t * __restrict attr,
401 size_t count, cpu_type_t *pref, size_t * __restrict ocount)
402{
403 _posix_spawnattr_t psattr;
404 int i = 0;
405
406 if (attr == NULL || *attr == NULL)
407 return EINVAL;
408
409 psattr = *(_posix_spawnattr_t *)attr;
410 for (i = 0; i < count && i < 4; i++) {
411 pref[i] = psattr->psa_binprefs[i];
412 }
413
414 if (ocount)
415 *ocount = i;
416 return 0;
417}
418
419
420/*
421 * posix_spawnattr_getpcontrol_np
422 *
423 * Description: Retrieve the process control property set default according to
424 * the spawn attribute value referenced by 'attr' and place the
425 * result into the memory containing the control referenced by
426 * 'pcontrol'
427 *
428 * Parameters: attr The spawn attributes object whose
429 * signal set for default signals is to
430 * be retrieved
431 * pcontrol A pointer to an int to receive
432 * the process control info
433 *
434 * Returns: 0 Success
435 *
436 * Implicit Returns:
437 * *pcontrol (modified) The signal set of signals to default
438 * from the spawn attributes object
439 */
440int
441posix_spawnattr_getpcontrol_np(const posix_spawnattr_t * __restrict attr,
442 int * __restrict pcontrol)
443{
444 _posix_spawnattr_t psattr;
445
446 if (attr == NULL || *attr == NULL)
447 return EINVAL;
448
449 psattr = *(_posix_spawnattr_t *)attr;
450 *pcontrol = psattr->psa_pcontrol;
451
452 return (0);
453}
454
455/*
456 * posix_spawnattr_getprocesstype_np
457 *
458 * Description: Retrieve the process specific behaviors and app launch types
459 * spawn attribute value referenced by 'attr' and place the
460 * result into the memory containing the control referenced by
461 * 'proctype'
462 *
463 * Parameters: attr The spawn attributes object whose
464 * signal set for default signals is to
465 * be retrieved
466 * proctype A pointer to an int to receive
467 * the process type info
468 *
469 * Returns: 0 Success
470 *
471 * Implicit Returns:
472 * *proctype (modified) The process type set to value
473 * from the spawn attributes object
474 */
475int
476posix_spawnattr_getprocesstype_np(const posix_spawnattr_t * __restrict attr,
477 int * __restrict proctype)
478{
479 _posix_spawnattr_t psattr;
480
481 if (attr == NULL || *attr == NULL)
482 return EINVAL;
483
484 psattr = *(_posix_spawnattr_t *)attr;
485 *proctype = psattr->psa_apptype;
486
487 return (0);
488}
489/*
490 * posix_spawnattr_setsigdefault
491 *
492 * Description: Set the set of signals to be set to default for the spawn
493 * attribute value referenced by 'attr' from the memory
494 * containing the sigset_t referenced by 'sigdefault'
495 *
496 * Parameters: attr The spawn attributes object whose
497 * signal set for default signals is to
498 * be set
499 * sigdefault A pointer to the sigset_t from which to
500 * obtain the signal set
501 *
502 * Returns: 0 Success
503 */
504int
505posix_spawnattr_setsigdefault(posix_spawnattr_t * __restrict attr,
506 const sigset_t * __restrict sigdefault)
507{
508 _posix_spawnattr_t psattr;
509
510 if (attr == NULL || *attr == NULL)
511 return EINVAL;
512
513 psattr = *(_posix_spawnattr_t *)attr;
514 psattr->psa_sigdefault = *sigdefault;
515
516 return (0);
517}
518
519
520/*
521 * posix_spawnattr_setpgroup
522 *
523 * Description: Set the value of the spawn process group attribute for the
524 * spawn attributes object referenced by 'attr' from the value
525 * of 'pgroup'
526 *
527 * Parameters: attr The spawn attributes object for which
528 * the process group information is to be
529 * set
530 * pgroup The process group to set
531 *
532 * Returns: 0 Success
533 */
534int
535posix_spawnattr_setpgroup(posix_spawnattr_t * attr, pid_t pgroup)
536{
537 _posix_spawnattr_t psattr;
538
539 if (attr == NULL || *attr == NULL)
540 return EINVAL;
541
542 psattr = *(_posix_spawnattr_t *)attr;
543 psattr->psa_pgroup = pgroup;
544
545 return (0);
546}
547
548
549/*
550 * posix_spawnattr_setsigmask
551 *
552 * Description: Set the set of signals to be masked for the spawn attribute
553 * value referenced by 'attr' from the memory containing the
554 * sigset_t referenced by 'sigmask'
555 *
556 * Parameters: attr The spawn attributes object whose
557 * signal set for masked signals is to
558 * be set
559 * sigmask A pointer to the sigset_t from which to
560 * obtain the signal set
561 *
562 * Returns: 0 Success
563 */
564int
565posix_spawnattr_setsigmask(posix_spawnattr_t * __restrict attr,
566 const sigset_t * __restrict sigmask)
567{
568 _posix_spawnattr_t psattr;
569
570 if (attr == NULL || *attr == NULL)
571 return EINVAL;
572
573 psattr = *(_posix_spawnattr_t *)attr;
574 psattr->psa_sigmask = *sigmask;
575
576 return (0);
577}
578
579
580/*
581 * posix_spawnattr_setbinpref_np
582 *
583 * Description: Set the universal binary preferences for the spawn attribute
584 * value referenced by 'attr' from the memory containing the
585 * cpu_type_t array referenced by 'pref', size of 'count'
586 *
587 * Parameters: attr The spawn attributes object whose
588 * binary preferences are to be set
589 * count Size of the array pointed to by 'pref'
590 * pref cpu_type_t array of binary preferences
591 * ocount The actual number copied
592 *
593 * Returns: 0 No preferences copied
594 * > 0 Number of preferences copied
595 *
596 * Note: The posix_spawnattr_t currently only holds four cpu_type_t's.
597 * If the caller provides more preferences than this limit, they
598 * will be ignored, as reflected in the return value.
599 */
600int
601posix_spawnattr_setbinpref_np(posix_spawnattr_t * __restrict attr,
602 size_t count, cpu_type_t *pref, size_t * __restrict ocount)
603{
604 _posix_spawnattr_t psattr;
605 int i = 0;
606
607 if (attr == NULL || *attr == NULL)
608 return EINVAL;
609
610 psattr = *(_posix_spawnattr_t *)attr;
611 for (i = 0; i < count && i < 4; i++) {
612 psattr->psa_binprefs[i] = pref[i];
613 }
614
615 /* return number of binprefs copied over */
616 if (ocount)
617 *ocount = i;
618 return 0;
619}
620
621
622/*
623 * posix_spawnattr_setpcontrol_np
624 *
625 * Description: Set the process control property according to
626 * attribute value referenced by 'attr' from the memory
627 * containing the int value 'pcontrol'
628 *
629 * Parameters: attr The spawn attributes object whose
630 * signal set for default signals is to
631 * be set
632 * pcontrol An int value of the process control info
633 *
634 * Returns: 0 Success
635 */
636int
637posix_spawnattr_setpcontrol_np(posix_spawnattr_t * __restrict attr,
638 const int pcontrol)
639{
640 _posix_spawnattr_t psattr;
641
642 if (attr == NULL || *attr == NULL)
643 return EINVAL;
644
645 psattr = *(_posix_spawnattr_t *)attr;
646 psattr->psa_pcontrol = pcontrol;
647
648 return (0);
649}
650
651
652/*
653 * posix_spawnattr_setprocesstype_np
654 *
655 * Description: Set the process specific behaviors and app launch type
656 * attribute value referenced by 'attr' from the memory
657 * containing the int value 'proctype'
658 *
659 * Parameters: attr The spawn attributes object whose
660 * signal set for default signals is to
661 * be set
662 * proctype An int value of the process type info
663 *
664 * Returns: 0 Success
665 */
666int
667posix_spawnattr_setprocesstype_np(posix_spawnattr_t * __restrict attr,
668 const int proctype)
669{
670 _posix_spawnattr_t psattr;
671
672 if (attr == NULL || *attr == NULL)
673 return EINVAL;
674
675 psattr = *(_posix_spawnattr_t *)attr;
676 psattr->psa_apptype = proctype;
677
678 return (0);
679}
680
681/*
682 * posix_spawn_createportactions_np
683 * Description: create a new posix_spawn_port_actions struct and link
684 * it into the posix_spawnattr.
685 */
686static int
687posix_spawn_createportactions_np(posix_spawnattr_t *attr)
688{
689 _posix_spawnattr_t psattr;
690 _posix_spawn_port_actions_t acts;
691
692 if (attr == NULL || *attr == NULL)
693 return EINVAL;
694
695 psattr = *(_posix_spawnattr_t *)attr;
696 acts = (_posix_spawn_port_actions_t)malloc(PS_PORT_ACTIONS_SIZE(2));
697 if (acts == NULL)
698 return ENOMEM;
699
700 acts->pspa_alloc = 2;
701 acts->pspa_count = 0;
702
703 psattr->psa_ports = acts;
704 return 0;
705}
706
707/*
708 * posix_spawn_growportactions_np
709 * Description: Enlarge the size of portactions if necessary
710 */
711static int
712posix_spawn_growportactions_np(posix_spawnattr_t *attr)
713{
714 _posix_spawnattr_t psattr;
715 _posix_spawn_port_actions_t acts;
39236c6e
A
716
717 if (attr == NULL || *attr == NULL)
718 return EINVAL;
719
720 psattr = *(_posix_spawnattr_t *)attr;
721 acts = psattr->psa_ports;
722 if (acts == NULL)
723 return EINVAL;
724
725 /* Double number of port actions allocated for */
5c9f4661
A
726 int newnum = 0;
727 if (os_mul_overflow(acts->pspa_alloc, 2, &newnum))
728 return ENOMEM;
729 size_t newsize = PS_PORT_ACTIONS_SIZE(newnum);
730 if (newsize == 0)
731 return ENOMEM;
732
733 acts = realloc(acts, newsize);
39236c6e
A
734 if (acts == NULL)
735 return ENOMEM;
736
737 acts->pspa_alloc = newnum;
738 psattr->psa_ports = acts;
739 return 0;
740}
741
742/*
743 * posix_spawn_destroyportactions_np
744 * Description: clean up portactions struct in posix_spawnattr_t attr
745 */
746static int
747posix_spawn_destroyportactions_np(posix_spawnattr_t *attr)
748{
749 _posix_spawnattr_t psattr;
750 _posix_spawn_port_actions_t acts;
751
752 if (attr == NULL || *attr == NULL)
753 return EINVAL;
754
755 psattr = *(_posix_spawnattr_t *)attr;
756 acts = psattr->psa_ports;
757 if (acts == NULL)
758 return EINVAL;
759
760 free(acts);
761 return 0;
762}
763
3e170ce0
A
764/*
765 * posix_spawn_destroycoalition_info_np
766 * Description: clean up coalition_info struct in posix_spawnattr_t attr
767 */
768static int
769posix_spawn_destroycoalition_info_np(posix_spawnattr_t *attr)
770{
771 _posix_spawnattr_t psattr;
772 struct _posix_spawn_coalition_info *coal_info;
773
774 if (attr == NULL || *attr == NULL)
775 return EINVAL;
776
777 psattr = *(_posix_spawnattr_t *)attr;
778 coal_info = psattr->psa_coalition_info;
779 if (coal_info == NULL)
780 return EINVAL;
781
782 psattr->psa_coalition_info = NULL;
783 free(coal_info);
784 return 0;
785}
786
490019cf
A
787/*
788 * posix_spawn_destroypersona_info_np
789 * Description: clean up persona_info struct in posix_spawnattr_t attr
790 */
791static int
792posix_spawn_destroypersona_info_np(posix_spawnattr_t *attr)
793{
794 _posix_spawnattr_t psattr;
795 struct _posix_spawn_persona_info *persona;
796
797 if (attr == NULL || *attr == NULL)
798 return EINVAL;
799
800 psattr = *(_posix_spawnattr_t *)attr;
801 persona = psattr->psa_persona_info;
802 if (persona == NULL)
803 return EINVAL;
804
805 psattr->psa_persona_info = NULL;
806 free(persona);
807 return 0;
808}
809
39236c6e
A
810/*
811 * posix_spawn_appendportaction_np
812 * Description: append a port action, grow the array if necessary
813 */
814static int
815posix_spawn_appendportaction_np(posix_spawnattr_t *attr, _ps_port_action_t *act)
816{
817 _posix_spawnattr_t psattr;
818 _posix_spawn_port_actions_t acts;
819
820 if (attr == NULL || *attr == NULL || act == NULL) {
821 return EINVAL;
822 }
823
824 psattr = *(_posix_spawnattr_t *)attr;
825 acts = psattr->psa_ports;
826
827 // Have any port actions been created yet?
828 if (acts == NULL) {
829 int err = posix_spawn_createportactions_np(attr);
830 if (err) {
831 return err;
832 }
833 acts = psattr->psa_ports;
834 }
835
836 // Is there enough room?
837 if (acts->pspa_alloc == acts->pspa_count) {
838 int err = posix_spawn_growportactions_np(attr);
839 if (err) {
840 return err;
841 }
842 acts = psattr->psa_ports;
843 }
844
845 // Add this action to next spot in array
846 acts->pspa_actions[acts->pspa_count] = *act;
847 acts->pspa_count++;
848
849 return 0;
850}
851
852/*
853 * posix_spawnattr_setspecialport_np
854 *
855 * Description: Set a new value for a mach special port in the spawned task.
856 *
857 * Parameters: attr The spawn attributes object for the
858 * new process
859 * new_port The new value for the special port
860 * which The particular port to be set
861 * (see task_set_special_port for details)
862 *
863 * Returns: 0 Success
864 * ENOMEM Couldn't allocate memory
865 */
866int
867posix_spawnattr_setspecialport_np(
868 posix_spawnattr_t *attr,
869 mach_port_t new_port,
870 int which)
871{
872 _ps_port_action_t action = {
873 .port_type = PSPA_SPECIAL,
874 .new_port = new_port,
875 .which = which,
876 };
877 return posix_spawn_appendportaction_np(attr, &action);
878}
879
880/*
881 * posix_spawnattr_setexceptionports_np
882 *
883 * Description: Set a new port for a set of exception ports in the spawned task.
884 *
885 * Parameters: attr The spawn attributes object for the
886 * new process
887 * mask A bitfield indicating which exceptions
888 * to associate the port with
889 * new_port The new value for the exception port
890 * behavior The default behavior for the port
891 * flavor The default flavor for the port
892 * (see task_set_exception_ports)
893 *
894 * Returns: 0 Success
895 */
896int
897posix_spawnattr_setexceptionports_np(
898 posix_spawnattr_t *attr,
899 exception_mask_t mask,
900 mach_port_t new_port,
901 exception_behavior_t behavior,
902 thread_state_flavor_t flavor)
903{
904 _ps_port_action_t action = {
905 .port_type = PSPA_EXCEPTION,
906 .mask = mask,
907 .new_port = new_port,
908 .behavior = behavior,
909 .flavor = flavor,
910 };
911 return posix_spawn_appendportaction_np(attr, &action);
912}
913
914/*
915 * posix_spawnattr_setauditsessionport_np
916 *
917 * Description: Set the audit session port rights attribute in the spawned task.
918 * This is used to securely set the audit session information for
919 * the new task.
920 *
921 * Parameters: attr The spawn attributes object for the
922 * new process
923 * au_sessionport The audit session send port right
924 *
925 * Returns: 0 Success
926 */
927int
928posix_spawnattr_setauditsessionport_np(
929 posix_spawnattr_t *attr,
930 mach_port_t au_sessionport)
931{
932 _ps_port_action_t action = {
933 .port_type = PSPA_AU_SESSION,
934 .new_port = au_sessionport,
935 };
936 return posix_spawn_appendportaction_np(attr, &action);
937}
938
939
940/*
941 * posix_spawn_file_actions_init
942 *
943 * Description: Initialize a spawn file actions object attr with default values
944 *
945 * Parameters: file_actions The spawn file actions object to be
946 * initialized
947 *
948 * Returns: 0 Success
949 * ENOMEM Insufficient memory exists to
950 * initialize the spawn file actions
951 * object.
952 *
953 * Note: As an implementation detail, the externally visibily type
954 * posix_spawn_file_actions_t is defined to be a void *, and
955 * initialization involves allocation of a memory object.
956 * Subsequent changes to the spawn file actions may result in
957 * reallocation under the covers.
958 *
959 * Reinitialization of an already initialized spawn file actions
960 * object will result in memory being leaked. Because spawn
961 * file actions are not required to be used in conjunction with a
962 * static initializer, there is no way to distinguish a spawn
963 * file actions with stack garbage from one that's been
964 * initialized. This is arguably an API design error.
965 */
966int
967posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions)
968{
969 _posix_spawn_file_actions_t *psactsp = (_posix_spawn_file_actions_t *)file_actions;
970 int err = 0;
971
972 if ((*psactsp = (_posix_spawn_file_actions_t)malloc(PSF_ACTIONS_SIZE(PSF_ACTIONS_INIT_COUNT))) == NULL) {
973 err = ENOMEM;
974 } else {
975 (*psactsp)->psfa_act_alloc = PSF_ACTIONS_INIT_COUNT;
976 (*psactsp)->psfa_act_count = 0;
977 }
978
979 return (err);
980}
981
982
983/*
984 * posix_spawn_file_actions_destroy
985 *
986 * Description: Destroy a spawn file actions object that was previously
987 * initialized via posix_spawn_file_actions_init() by freeing any
988 * memory associated with it and setting it to an invalid value.
989 *
990 * Parameters: attr The spawn file actions object to be
991 * destroyed.
992 *
993 * Returns: 0 Success
994 *
995 * Notes: The destroyed spawn file actions results in the void * pointer
996 * being set to NULL; subsequent use without reinitialization
997 * will result in explicit program failure (rather than merely
998 * "undefined behaviour").
999 *
1000 * NOTIMP: Allowed failures (checking NOT required):
1001 * EINVAL The value specified by file_actions is invalid.
1002 */
1003int
1004posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions)
1005{
1006 _posix_spawn_file_actions_t psacts;
1007
1008 if (file_actions == NULL || *file_actions == NULL)
1009 return EINVAL;
1010
1011 psacts = *(_posix_spawn_file_actions_t *)file_actions;
1012 free(psacts);
1013 *file_actions = NULL;
1014
1015 return (0);
1016}
1017
1018
1019/*
1020 * _posix_spawn_file_actions_grow
1021 *
1022 * Description: Grow the available list of file actions associated with the
1023 * pointer to the structure provided; replace the contents of the
1024 * pointer as a side effect.
1025 *
1026 * Parameters: psactsp Pointer to _posix_spawn_file_actions_t
1027 * to grow
1028 *
1029 * Returns: 0 Success
1030 * ENOMEM Insufficient memory for operation
1031 *
1032 * Notes: This code is common to all posix_spawn_file_actions_*()
1033 * functions, since we use a naieve data structure implementation
1034 * at present. Future optimization will likely change this.
1035 */
1036static int
1037_posix_spawn_file_actions_grow(_posix_spawn_file_actions_t *psactsp)
1038{
5c9f4661
A
1039 int newnum = 0;
1040 if (os_mul_overflow((*psactsp)->psfa_act_alloc, 2, &newnum))
1041 return ENOMEM;
1042
1043 size_t newsize = PSF_ACTIONS_SIZE(newnum);
1044 if (newsize == 0)
1045 return ENOMEM;
39236c6e
A
1046
1047 /*
1048 * XXX may want to impose an administrative limit here; POSIX does
1049 * XXX not provide for an administrative error return in this case,
1050 * XXX so it's probably acceptable to just fail catastrophically
1051 * XXX instead of implementing one.
1052 */
5c9f4661
A
1053 _posix_spawn_file_actions_t new_psacts;
1054 if ((new_psacts = (_posix_spawn_file_actions_t)realloc((*psactsp), newsize)) == NULL) {
1055 return ENOMEM;
39236c6e 1056 }
5c9f4661 1057 new_psacts->psfa_act_alloc = newnum;
39236c6e
A
1058 *psactsp = new_psacts;
1059
5c9f4661 1060 return 0;
39236c6e
A
1061}
1062
1063
1064/*
1065 * posix_spawn_file_actions_addopen
1066 *
1067 * Description: Add an open action to the object referenced by 'file_actions'
1068 * that will cause the file named by 'path' to be attempted to be
1069 * opened with flags 'oflag' and mode 'mode', and, if successful,
1070 * return as descriptor 'filedes' to the spawned process.
1071 *
1072 * Parameters: file_actions File action object to augment
1073 * filedes fd that open is to use
1074 * path path to file to open
1075 * oflag open file flags
1076 * mode open file mode
1077 *
1078 * Returns: 0 Success
1079 * EBADF The value specified by fildes is
1080 * negative or greater than or equal to
1081 * {OPEN_MAX}.
1082 * ENOMEM Insufficient memory exists to add to
1083 * the spawn file actions object.
1084 *
1085 * NOTIMP: Allowed failures (checking NOT required):
1086 * EINVAL The value specified by file_actions is invalid.
1087 */
1088int
1089posix_spawn_file_actions_addopen(
1090 posix_spawn_file_actions_t * __restrict file_actions,
1091 int filedes, const char * __restrict path, int oflag,
1092 mode_t mode)
1093{
1094 _posix_spawn_file_actions_t *psactsp;
1095 _psfa_action_t *psfileact;
1096
1097 if (file_actions == NULL || *file_actions == NULL)
1098 return EINVAL;
1099
1100 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1101 /* Range check; required by POSIX */
1102 if (filedes < 0 || filedes >= OPEN_MAX)
1103 return (EBADF);
1104
1105 /* If we do not have enough slots, grow the structure */
1106 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1107 /* need to grow file actions structure */
1108 if (_posix_spawn_file_actions_grow(psactsp))
1109 return (ENOMEM);
1110 }
1111
1112 /*
1113 * Allocate next available slot and fill it out
1114 */
1115 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1116
1117 psfileact->psfaa_type = PSFA_OPEN;
1118 psfileact->psfaa_filedes = filedes;
1119 psfileact->psfaa_openargs.psfao_oflag = oflag;
1120 psfileact->psfaa_openargs.psfao_mode = mode;
1121 strlcpy(psfileact->psfaa_openargs.psfao_path, path, PATH_MAX);
1122
1123 return (0);
1124}
1125
1126
1127/*
1128 * posix_spawn_file_actions_addclose
1129 *
1130 * Description: Add a close action to the object referenced by 'file_actions'
1131 * that will cause the file referenced by 'filedes' to be
1132 * attempted to be closed in the spawned process.
1133 *
1134 * Parameters: file_actions File action object to augment
1135 * filedes fd to close
1136 *
1137 * Returns: 0 Success
1138 * EBADF The value specified by fildes is
1139 * negative or greater than or equal to
1140 * {OPEN_MAX}.
1141 * ENOMEM Insufficient memory exists to add to
1142 * the spawn file actions object.
1143 *
1144 * NOTIMP: Allowed failures (checking NOT required):
1145 * EINVAL The value specified by file_actions is invalid.
1146 */
1147int
1148posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions,
1149 int filedes)
1150{
1151 _posix_spawn_file_actions_t *psactsp;
1152 _psfa_action_t *psfileact;
1153
1154 if (file_actions == NULL || *file_actions == NULL)
1155 return EINVAL;
1156
1157 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1158 /* Range check; required by POSIX */
1159 if (filedes < 0 || filedes >= OPEN_MAX)
1160 return (EBADF);
1161
1162 /* If we do not have enough slots, grow the structure */
1163 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1164 /* need to grow file actions structure */
1165 if (_posix_spawn_file_actions_grow(psactsp))
1166 return (ENOMEM);
1167 }
1168
1169 /*
1170 * Allocate next available slot and fill it out
1171 */
1172 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1173
1174 psfileact->psfaa_type = PSFA_CLOSE;
1175 psfileact->psfaa_filedes = filedes;
1176
1177 return (0);
1178}
1179
1180
1181/*
1182 * posix_spawn_file_actions_adddup2
1183 *
1184 * Description: Add a dup2 action to the object referenced by 'file_actions'
1185 * that will cause the file referenced by 'filedes' to be
1186 * attempted to be dup2'ed to the descriptor 'newfiledes' in the
1187 * spawned process.
1188 *
1189 * Parameters: file_actions File action object to augment
1190 * filedes fd to dup2
1191 * newfiledes fd to dup2 it to
1192 *
1193 * Returns: 0 Success
1194 * EBADF The value specified by either fildes
1195 * or by newfiledes is negative or greater
1196 * than or equal to {OPEN_MAX}.
1197 * ENOMEM Insufficient memory exists to add to
1198 * the spawn file actions object.
1199 *
1200 * NOTIMP: Allowed failures (checking NOT required):
1201 * EINVAL The value specified by file_actions is invalid.
1202 */
1203int
1204posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions,
1205 int filedes, int newfiledes)
1206{
1207 _posix_spawn_file_actions_t *psactsp;
1208 _psfa_action_t *psfileact;
1209
1210 if (file_actions == NULL || *file_actions == NULL)
1211 return EINVAL;
1212
1213 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1214 /* Range check; required by POSIX */
1215 if (filedes < 0 || filedes >= OPEN_MAX ||
1216 newfiledes < 0 || newfiledes >= OPEN_MAX)
1217 return (EBADF);
1218
1219 /* If we do not have enough slots, grow the structure */
1220 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1221 /* need to grow file actions structure */
1222 if (_posix_spawn_file_actions_grow(psactsp))
1223 return (ENOMEM);
1224 }
1225
1226 /*
1227 * Allocate next available slot and fill it out
1228 */
1229 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1230
1231 psfileact->psfaa_type = PSFA_DUP2;
1232 psfileact->psfaa_filedes = filedes;
1233 psfileact->psfaa_openargs.psfao_oflag = newfiledes;
1234
1235 return (0);
1236}
1237
1238/*
1239 * posix_spawn_file_actions_addinherit_np
1240 *
1241 * Description: Add the "inherit" action to the object referenced by
1242 * 'file_actions' that will cause the file referenced by
1243 * 'filedes' to continue to be available in the spawned
1244 * process via the same descriptor.
1245 *
1246 * Inheritance is the normal default behaviour for
1247 * file descriptors across exec and spawn; but if the
1248 * POSIX_SPAWN_CLOEXEC_DEFAULT flag is set, the usual
1249 * default is reversed for the purposes of the spawn
1250 * invocation. Any pre-existing descriptors that
1251 * need to be made available to the spawned process can
1252 * be marked explicitly as 'inherit' via this interface.
1253 * Otherwise they will be automatically closed.
1254 *
1255 * Note that any descriptors created via the other file
1256 * actions interfaces are automatically marked as 'inherit'.
1257 *
1258 * Parameters: file_actions File action object to augment
1259 * filedes fd to inherit.
1260 *
1261 * Returns: 0 Success
1262 * EBADF The value specified by fildes is
1263 * negative or greater than or equal to
1264 * {OPEN_MAX}.
1265 * ENOMEM Insufficient memory exists to add to
1266 * the spawn file actions object.
1267 *
1268 * NOTIMP: Allowed failures (checking NOT required):
1269 * EINVAL The value specified by file_actions is invalid.
1270 */
1271int
1272posix_spawn_file_actions_addinherit_np(posix_spawn_file_actions_t *file_actions,
1273 int filedes)
1274{
1275 _posix_spawn_file_actions_t *psactsp;
1276 _psfa_action_t *psfileact;
1277
1278 if (file_actions == NULL || *file_actions == NULL)
1279 return (EINVAL);
1280
1281 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1282 /* Range check; required by POSIX */
1283 if (filedes < 0 || filedes >= OPEN_MAX)
1284 return (EBADF);
1285
1286#if defined(POSIX_SPAWN_CLOEXEC_DEFAULT) // TODO: delete this check
1287 /* If we do not have enough slots, grow the structure */
1288 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1289 /* need to grow file actions structure */
1290 if (_posix_spawn_file_actions_grow(psactsp))
1291 return (ENOMEM);
1292 }
1293
1294 /*
1295 * Allocate next available slot and fill it out
1296 */
1297 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1298
1299 psfileact->psfaa_type = PSFA_INHERIT;
1300 psfileact->psfaa_filedes = filedes;
1301#endif
1302 return (0);
1303}
1304
1305int
1306posix_spawnattr_setcpumonitor_default(posix_spawnattr_t * __restrict attr)
1307{
1308 return (posix_spawnattr_setcpumonitor(attr, PROC_POLICY_CPUMON_DEFAULTS, 0));
1309}
1310
1311int
1312posix_spawnattr_setcpumonitor(posix_spawnattr_t * __restrict attr,
1313 uint64_t percent, uint64_t interval)
1314{
1315 _posix_spawnattr_t psattr;
1316
1317 if (attr == NULL || *attr == NULL)
1318 return (EINVAL);
1319
1320 psattr = *(_posix_spawnattr_t *)attr;
1321
1322 psattr->psa_cpumonitor_percent = percent;
1323 psattr->psa_cpumonitor_interval = interval;
1324
1325 return (0);
1326}
1327
1328int
1329posix_spawnattr_getcpumonitor(posix_spawnattr_t * __restrict attr,
1330 uint64_t *percent, uint64_t *interval)
1331{
1332 _posix_spawnattr_t psattr;
1333
1334 if (attr == NULL || *attr == NULL)
1335 return (EINVAL);
1336
1337 psattr = *(_posix_spawnattr_t *)attr;
1338
1339 *percent = psattr->psa_cpumonitor_percent;
1340 *interval = psattr->psa_cpumonitor_interval;
1341
1342 return (0);
1343}
1344
5ba3f43e
A
1345#if TARGET_OS_EMBEDDED
1346/*
1347 * posix_spawnattr_setjetsam
1348 *
1349 * Description: Set jetsam attributes for the spawn attribute object
1350 * referred to by 'attr'.
1351 *
1352 * Parameters: flags The flags value to set
1353 * priority Relative jetsam priority
1354 * memlimit Value in megabytes; a memory footprint
1355 * above this level may result in termination.
1356 * Implies both active and inactive limits.
1357 *
1358 * Returns: 0 Success
1359 *
1360 * Note: to be deprecated (not available on desktop)
1361 *
1362 */
1363int
1364posix_spawnattr_setjetsam(posix_spawnattr_t * __restrict attr,
1365 short flags, int priority, int memlimit)
1366{
1367 short flags_ext = flags;
1368
1369 if (flags & POSIX_SPAWN_JETSAM_MEMLIMIT_FATAL) {
1370 flags_ext |= POSIX_SPAWN_JETSAM_MEMLIMIT_ACTIVE_FATAL;
1371 flags_ext |= POSIX_SPAWN_JETSAM_MEMLIMIT_INACTIVE_FATAL;
1372 } else {
1373 flags_ext &= ~POSIX_SPAWN_JETSAM_MEMLIMIT_ACTIVE_FATAL;
1374 flags_ext &= ~POSIX_SPAWN_JETSAM_MEMLIMIT_INACTIVE_FATAL;
1375 }
1376
1377 return (posix_spawnattr_setjetsam_ext(attr, flags_ext, priority, memlimit, memlimit));
1378}
1379#endif /* TARGET_OS_EMBEDDED */
39236c6e 1380
39037602
A
1381/*
1382 * posix_spawnattr_setjetsam_ext
1383 *
1384 * Description: Set jetsam attributes for the spawn attribute object
1385 * referred to by 'attr'.
1386 *
1387 * Parameters: flags The flags value to set
1388 * priority Relative jetsam priority
1389 * memlimit_active Value in megabytes; memory footprint
1390 * above this level while process is
1391 * active may result in termination.
1392 * memlimit_inactive Value in megabytes; memory footprint
1393 * above this level while process is
1394 * inactive may result in termination.
1395 *
1396 * Returns: 0 Success
1397 */
1398int
1399posix_spawnattr_setjetsam_ext(posix_spawnattr_t * __restrict attr,
1400 short flags, int priority, int memlimit_active, int memlimit_inactive)
1401{
1402 _posix_spawnattr_t psattr;
1403
1404 if (attr == NULL || *attr == NULL)
1405 return EINVAL;
1406
1407 psattr = *(_posix_spawnattr_t *)attr;
1408
1409 psattr->psa_jetsam_flags = flags;
1410 psattr->psa_jetsam_flags |= POSIX_SPAWN_JETSAM_SET;
1411 psattr->psa_priority = priority;
1412 psattr->psa_memlimit_active = memlimit_active;
1413 psattr->psa_memlimit_inactive = memlimit_inactive;
1414
1415 return (0);
1416}
1417
39236c6e
A
1418
1419/*
1420 * posix_spawnattr_set_importancewatch_port_np
1421 *
1422 * Description: Mark ports referred to by these rights
1423 * to boost the new task instead of their current task
1424 * for the spawn attribute object referred to by 'attr'.
1425 * Ports must be valid at posix_spawn time. They will NOT be
1426 * consumed by the kernel, so they must be deallocated after the spawn returns.
1427 * (If you are SETEXEC-ing, they are cleaned up by the exec operation).
1428 *
1429 * The maximum number of watch ports allowed is defined by POSIX_SPAWN_IMPORTANCE_PORT_COUNT.
1430 *
1431 * Parameters: count Number of ports in portarray
1432 * portarray Array of rights
1433 *
1434 * Returns: 0 Success
1435 * EINVAL Bad port count
1436 * ENOMEM Insufficient memory exists to add to
1437 * the spawn port actions object.
1438 */
1439int
1440posix_spawnattr_set_importancewatch_port_np(posix_spawnattr_t * __restrict attr,
1441 int count, mach_port_t portarray[])
1442{
1443 int err = 0, i;
1444
1445 if (count < 0 || count > POSIX_SPAWN_IMPORTANCE_PORT_COUNT) {
1446 return EINVAL;
1447 }
1448
1449 for (i = 0; i < count; i++) {
1450 _ps_port_action_t action = {
1451 .port_type = PSPA_IMP_WATCHPORTS,
1452 .new_port = portarray[i],
1453 };
1454 int err = posix_spawn_appendportaction_np(attr, &action);
1455 if (err) {
1456 break;
1457 }
1458 }
1459 return err;
1460}
1461
1462
1463
1464static
1465_ps_mac_policy_extension_t *
1466posix_spawnattr_macpolicyinfo_lookup(_posix_spawn_mac_policy_extensions_t psmx, const char *policyname)
1467{
1468 int i;
1469
1470 if (psmx == NULL)
1471 return NULL;
1472
1473 for (i = 0; i < psmx->psmx_count; i++) {
1474 _ps_mac_policy_extension_t *extension = &psmx->psmx_extensions[i];
1475 if (strcmp(extension->policyname, policyname) == 0)
1476 return extension;
1477 }
1478 return NULL;
1479}
1480
1481int
1482posix_spawnattr_getmacpolicyinfo_np(const posix_spawnattr_t * __restrict attr,
1483 const char *policyname, void **datap, size_t *datalenp)
1484{
1485 _posix_spawnattr_t psattr;
1486 _ps_mac_policy_extension_t *extension;
1487
1488 if (attr == NULL || *attr == NULL || policyname == NULL || datap == NULL)
1489 return EINVAL;
1490
1491 psattr = *(_posix_spawnattr_t *)attr;
1492 extension = posix_spawnattr_macpolicyinfo_lookup(psattr->psa_mac_extensions, policyname);
1493 if (extension == NULL)
1494 return ESRCH;
1495 *datap = (void *)(uintptr_t)extension->data;
fe8ab488
A
1496 if (datalenp != NULL) {
1497 *datalenp = (size_t)extension->datalen;
1498 }
39236c6e
A
1499 return 0;
1500}
1501
1502int
1503posix_spawnattr_setmacpolicyinfo_np(posix_spawnattr_t * __restrict attr,
1504 const char *policyname, void *data, size_t datalen)
1505{
1506 _posix_spawnattr_t psattr;
1507 _posix_spawn_mac_policy_extensions_t psmx;
1508 _ps_mac_policy_extension_t *extension;
1509
1510 if (attr == NULL || *attr == NULL || policyname == NULL)
1511 return EINVAL;
1512
1513 psattr = *(_posix_spawnattr_t *)attr;
1514 psmx = psattr->psa_mac_extensions;
1515 extension = posix_spawnattr_macpolicyinfo_lookup(psattr->psa_mac_extensions, policyname);
1516 if (extension != NULL) {
1517 extension->data = (uintptr_t)data;
1518 extension->datalen = datalen;
1519 return 0;
1520 }
1521 else if (psmx == NULL) {
1522 psmx = psattr->psa_mac_extensions = malloc(PS_MAC_EXTENSIONS_SIZE(PS_MAC_EXTENSIONS_INIT_COUNT));
1523 if (psmx == NULL)
1524 return ENOMEM;
1525 psmx->psmx_alloc = PS_MAC_EXTENSIONS_INIT_COUNT;
1526 psmx->psmx_count = 0;
1527 }
1528 else if (psmx->psmx_count == psmx->psmx_alloc) {
5c9f4661
A
1529 int newnum = 0;
1530 if (os_mul_overflow(psmx->psmx_alloc, 2, &newnum))
1531 return ENOMEM;
1532 size_t extsize = PS_MAC_EXTENSIONS_SIZE(newnum);
1533 if (extsize == 0)
1534 return ENOMEM;
1535 psmx = psattr->psa_mac_extensions = reallocf(psmx, extsize);
39236c6e
A
1536 if (psmx == NULL)
1537 return ENOMEM;
5c9f4661 1538 psmx->psmx_alloc = newnum;
39236c6e
A
1539 }
1540 extension = &psmx->psmx_extensions[psmx->psmx_count];
1541 strlcpy(extension->policyname, policyname, sizeof(extension->policyname));
1542 extension->data = (uintptr_t)data;
1543 extension->datalen = datalen;
1544 psmx->psmx_count += 1;
1545 return 0;
1546}
1547
3e170ce0
A
1548int posix_spawnattr_setcoalition_np(const posix_spawnattr_t * __restrict attr,
1549 uint64_t coalitionid, int type, int role)
fe8ab488
A
1550{
1551 _posix_spawnattr_t psattr;
3e170ce0 1552 struct _posix_spawn_coalition_info *coal_info;
fe8ab488
A
1553
1554 if (attr == NULL || *attr == NULL) {
1555 return EINVAL;
1556 }
3e170ce0
A
1557 if (type < 0 || type > COALITION_TYPE_MAX)
1558 return EINVAL;
fe8ab488
A
1559
1560 psattr = *(_posix_spawnattr_t *)attr;
3e170ce0
A
1561
1562 coal_info = psattr->psa_coalition_info;
1563 if (!coal_info) {
1564 coal_info = (struct _posix_spawn_coalition_info *)malloc(sizeof(*coal_info));
1565 if (!coal_info)
1566 return ENOMEM;
1567 memset(coal_info, 0, sizeof(*coal_info));
1568 psattr->psa_coalition_info = coal_info;
1569 }
1570
1571 coal_info->psci_info[type].psci_id = coalitionid;
1572 coal_info->psci_info[type].psci_role = role;
fe8ab488
A
1573
1574 return 0;
1575}
1576
1577
1578int posix_spawnattr_set_qos_clamp_np(const posix_spawnattr_t * __restrict attr, uint64_t qos_clamp)
1579{
1580 _posix_spawnattr_t psattr;
1581
1582 if (attr == NULL || *attr == NULL) {
1583 return EINVAL;
1584 }
1585
1586 if (qos_clamp >= POSIX_SPAWN_PROC_CLAMP_LAST)
1587 return EINVAL;
1588
1589 psattr = *(_posix_spawnattr_t *)attr;
1590 psattr->psa_qos_clamp = qos_clamp;
1591
1592 return 0;
1593}
1594
1595int
1596posix_spawnattr_get_qos_clamp_np(const posix_spawnattr_t * __restrict attr, uint64_t * __restrict qos_clampp)
1597{
1598 _posix_spawnattr_t psattr;
1599
1600 if (attr == NULL || *attr == NULL) {
1601 return EINVAL;
1602 }
1603
1604 psattr = *(_posix_spawnattr_t *)attr;
1605 *qos_clampp = psattr->psa_qos_clamp;
1606
1607 return (0);
1608}
1609
3e170ce0
A
1610int posix_spawnattr_set_darwin_role_np(const posix_spawnattr_t * __restrict attr, uint64_t darwin_role)
1611{
1612 _posix_spawnattr_t psattr;
1613
1614 if (attr == NULL || *attr == NULL) {
1615 return EINVAL;
1616 }
1617
1618 psattr = *(_posix_spawnattr_t *)attr;
1619 psattr->psa_darwin_role = darwin_role;
1620
1621 return 0;
1622}
1623
1624int
1625posix_spawnattr_get_darwin_role_np(const posix_spawnattr_t * __restrict attr, uint64_t * __restrict darwin_rolep)
1626{
1627 _posix_spawnattr_t psattr;
1628
1629 if (attr == NULL || *attr == NULL) {
1630 return EINVAL;
1631 }
1632
1633 psattr = *(_posix_spawnattr_t *)attr;
1634 *darwin_rolep = psattr->psa_darwin_role;
1635
1636 return (0);
1637}
fe8ab488 1638
490019cf
A
1639
1640int
1641posix_spawnattr_set_persona_np(const posix_spawnattr_t * __restrict attr, uid_t persona_id, uint32_t flags)
1642{
1643 _posix_spawnattr_t psattr;
1644 struct _posix_spawn_persona_info *persona;
1645
1646 if (attr == NULL || *attr == NULL)
1647 return EINVAL;
1648
1649 if (flags & ~POSIX_SPAWN_PERSONA_ALL_FLAGS)
1650 return EINVAL;
1651
1652 psattr = *(_posix_spawnattr_t *)attr;
1653
1654 persona = psattr->psa_persona_info;
1655 if (!persona) {
1656 persona = (struct _posix_spawn_persona_info *)malloc(sizeof(*persona));
1657 if (!persona)
1658 return ENOMEM;
1659 persona->pspi_uid = 0;
1660 persona->pspi_gid = 0;
1661 persona->pspi_ngroups = 0;
1662 persona->pspi_groups[0] = 0;
1663
1664 psattr->psa_persona_info = persona;
1665 }
1666
1667 persona->pspi_id = persona_id;
1668 persona->pspi_flags = flags;
1669
1670 return 0;
1671}
1672
1673int
1674posix_spawnattr_set_persona_uid_np(const posix_spawnattr_t * __restrict attr, uid_t uid)
1675{
1676 _posix_spawnattr_t psattr;
1677 struct _posix_spawn_persona_info *persona;
1678
1679 if (attr == NULL || *attr == NULL)
1680 return EINVAL;
1681
1682 psattr = *(_posix_spawnattr_t *)attr;
1683 persona = psattr->psa_persona_info;
1684 if (!persona)
1685 return EINVAL;
1686
1687 if (!(persona->pspi_flags & (POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE | POSIX_SPAWN_PERSONA_FLAGS_VERIFY)))
1688 return EINVAL;
1689
1690 persona->pspi_uid = uid;
1691
1692 persona->pspi_flags |= POSIX_SPAWN_PERSONA_UID;
1693
1694 return 0;
1695}
1696
1697int
1698posix_spawnattr_set_persona_gid_np(const posix_spawnattr_t * __restrict attr, gid_t gid)
1699{
1700 _posix_spawnattr_t psattr;
1701 struct _posix_spawn_persona_info *persona;
1702
1703 if (attr == NULL || *attr == NULL)
1704 return EINVAL;
1705
1706 psattr = *(_posix_spawnattr_t *)attr;
1707 persona = psattr->psa_persona_info;
1708 if (!persona)
1709 return EINVAL;
1710
1711 if (!(persona->pspi_flags & (POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE | POSIX_SPAWN_PERSONA_FLAGS_VERIFY)))
1712 return EINVAL;
1713
1714 persona->pspi_gid = gid;
1715
1716 persona->pspi_flags |= POSIX_SPAWN_PERSONA_GID;
1717
1718 return 0;
1719}
1720
1721int
1722posix_spawnattr_set_persona_groups_np(const posix_spawnattr_t * __restrict attr, int ngroups, gid_t *gidarray, uid_t gmuid)
1723{
1724 _posix_spawnattr_t psattr;
1725 struct _posix_spawn_persona_info *persona;
1726
1727 if (attr == NULL || *attr == NULL)
1728 return EINVAL;
1729
1730 if (gidarray == NULL)
1731 return EINVAL;
1732
527f9951 1733 if (ngroups > NGROUPS || ngroups < 0)
490019cf
A
1734 return EINVAL;
1735
1736 psattr = *(_posix_spawnattr_t *)attr;
1737 persona = psattr->psa_persona_info;
1738 if (!persona)
1739 return EINVAL;
1740
1741 if (!(persona->pspi_flags & (POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE | POSIX_SPAWN_PERSONA_FLAGS_VERIFY)))
1742 return EINVAL;
1743
1744 persona->pspi_ngroups = ngroups;
1745 for (int i = 0; i < ngroups; i++)
1746 persona->pspi_groups[i] = gidarray[i];
1747
1748 persona->pspi_gmuid = gmuid;
1749
1750 persona->pspi_flags |= POSIX_SPAWN_PERSONA_GROUPS;
1751
1752 return 0;
1753}
1754
1755
1756
39236c6e
A
1757/*
1758 * posix_spawn
1759 *
1760 * Description: Create a new process from the process image corresponding to
1761 * the supplied 'path' argument.
1762 *
1763 * Parameters: pid Pointer to pid_t to receive the
1764 * PID of the spawned process, if
1765 * successful and 'pid' != NULL
1766 * path Path of image file to spawn
1767 * file_actions spawn file actions object which
1768 * describes file actions to be
1769 * performed during the spawn
1770 * attrp spawn attributes object which
1771 * describes attributes to be
1772 * applied during the spawn
1773 * argv argument vector array; NULL
1774 * terminated
1775 * envp environment vector array; NULL
1776 * terminated
1777 *
1778 * Returns: 0 Success
1779 * !0 An errno value indicating the
1780 * cause of the failure to spawn
1781 *
1782 * Notes: Unlike other system calls, the return value of this system
1783 * call is expected to either be a 0 or an errno, rather than a
1784 * 0 or a -1, with the 'errno' variable being set.
1785 */
1786extern int __posix_spawn(pid_t * __restrict, const char * __restrict,
1787 struct _posix_spawn_args_desc *,
1788 char *const argv[ __restrict], char *const envp[ __restrict]);
1789
1790int
1791posix_spawn(pid_t * __restrict pid, const char * __restrict path,
1792 const posix_spawn_file_actions_t *file_actions,
1793 const posix_spawnattr_t * __restrict attrp,
1794 char *const argv[ __restrict], char *const envp[ __restrict])
1795{
1796 int saveerrno = errno;
1797 int ret;
1798 /*
1799 * Only do extra work if we have file actions or attributes to push
1800 * down. We use a descriptor to push this information down, since we
1801 * want to have size information, which will let us (1) preallocate a
1802 * single chunk of memory for the copyin(), and (2) allow us to do a
1803 * single copyin() per attributes or file actions as a monlithic block.
1804 *
1805 * Note: A future implementation may attempt to do the same
1806 * thing for the argv/envp data, which could potentially
1807 * result in a performance improvement due to increased
1808 * kernel efficiency, even though it would mean copying
1809 * the data in user space.
1810 */
1811 if ((file_actions != NULL && (*file_actions != NULL) && (*(_posix_spawn_file_actions_t *)file_actions)->psfa_act_count > 0) || attrp != NULL) {
1812 struct _posix_spawn_args_desc ad;
1813
1814 memset(&ad, 0, sizeof(ad));
1815 if (attrp != NULL && *attrp != NULL) {
1816 _posix_spawnattr_t psattr = *(_posix_spawnattr_t *)attrp;
1817 ad.attr_size = sizeof(struct _posix_spawnattr);
1818 ad.attrp = psattr;
1819
1820 if (psattr->psa_ports != NULL) {
5c9f4661
A
1821 size_t psact_size = PS_PORT_ACTIONS_SIZE(psattr->psa_ports->pspa_count);
1822 if (psact_size == 0 && psattr->psa_ports->pspa_count != 0) {
1823 errno = EINVAL;
1824 ret = -1;
1825 goto out;
1826 }
39236c6e 1827 ad.port_actions = psattr->psa_ports;
5c9f4661 1828 ad.port_actions_size = psact_size;
39236c6e
A
1829 }
1830 if (psattr->psa_mac_extensions != NULL) {
5c9f4661
A
1831 size_t macext_size = PS_MAC_EXTENSIONS_SIZE(psattr->psa_mac_extensions->psmx_count);
1832 if (macext_size == 0 && psattr->psa_mac_extensions->psmx_count != 0) {
1833 errno = EINVAL;
1834 ret = -1;
1835 goto out;
1836 }
39236c6e 1837 ad.mac_extensions = psattr->psa_mac_extensions;
5c9f4661 1838 ad.mac_extensions_size = macext_size;
39236c6e 1839 }
3e170ce0
A
1840 if (psattr->psa_coalition_info != NULL) {
1841 ad.coal_info_size = sizeof(struct _posix_spawn_coalition_info);
1842 ad.coal_info = psattr->psa_coalition_info;
1843 }
490019cf
A
1844 if (psattr->psa_persona_info != NULL) {
1845 ad.persona_info_size = sizeof(struct _posix_spawn_persona_info);
1846 ad.persona_info = psattr->psa_persona_info;
1847 }
39236c6e
A
1848 }
1849 if (file_actions != NULL && *file_actions != NULL) {
1850 _posix_spawn_file_actions_t psactsp =
1851 *(_posix_spawn_file_actions_t *)file_actions;
1852
1853 if (psactsp->psfa_act_count > 0) {
5c9f4661
A
1854 size_t fa_size = PSF_ACTIONS_SIZE(psactsp->psfa_act_count);
1855 if (fa_size == 0 && psactsp->psfa_act_count != 0) {
1856 errno = EINVAL;
1857 ret = -1;
1858 goto out;
1859 }
1860 ad.file_actions_size = fa_size;
39236c6e
A
1861 ad.file_actions = psactsp;
1862 }
1863 }
1864
1865 ret = __posix_spawn(pid, path, &ad, argv, envp);
1866 } else
1867 ret = __posix_spawn(pid, path, NULL, argv, envp);
1868
5c9f4661 1869out:
39236c6e
A
1870 if (ret < 0)
1871 ret = errno;
1872 errno = saveerrno;
1873 return ret;
1874}
1875