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