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