]> git.saurik.com Git - apple/xnu.git/blob - libsyscall/wrappers/spawn/posix_spawn.c
xnu-6153.101.6.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/mach_param.h> /* for TASK_PORT_REGISTER_MAX */
41 #include <mach/exception_types.h>
42 #include <mach/coalition.h> /* for COALITION_TYPE_MAX */
43 #include <sys/kern_memorystatus.h>
44
45 /*
46 * posix_spawnattr_init
47 *
48 * Description: Initialize a spawn attributes object attr with default values
49 *
50 * Parameters: attr The spawn attributes object to be
51 * initialized
52 *
53 * Returns: 0 Success
54 * ENOMEM Insufficient memory exists to
55 * initialize the spawn attributes object.
56 *
57 * Note: As an implementation detail, the externally visibily type
58 * posix_spawnattr_t is defined to be a void *, and initialization
59 * involves allocation of a memory object. Subsequent changes to
60 * the spawn attributes may result in reallocation under the
61 * covers.
62 *
63 * Reinitialization of an already initialized spawn attributes
64 * object will result in memory being leaked. Because spawn
65 * attributes are not required to be used in conjunction with a
66 * static initializer, there is no way to distinguish a spawn
67 * attribute with stack garbage from one that's been initialized.
68 * This is arguably an API design error.
69 */
70 int
71 posix_spawnattr_init(posix_spawnattr_t *attr)
72 {
73 _posix_spawnattr_t *psattrp = (_posix_spawnattr_t *)attr;
74 int err = 0;
75
76 if ((*psattrp = (_posix_spawnattr_t)malloc(sizeof(struct _posix_spawnattr))) == NULL) {
77 err = ENOMEM;
78 } else {
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;
116
117 /* Default is no new apptype requested */
118 (*psattrp)->psa_apptype = POSIX_SPAWN_PROCESS_TYPE_DEFAULT;
119
120 /* Jetsam related */
121 (*psattrp)->psa_jetsam_flags = 0;
122 (*psattrp)->psa_priority = -1;
123 (*psattrp)->psa_memlimit_active = -1;
124 (*psattrp)->psa_memlimit_inactive = -1;
125
126 /* Default is no thread limit */
127 (*psattrp)->psa_thread_limit = 0;
128
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;
135
136 /* Default is to inherit parent's coalition(s) */
137 (*psattrp)->psa_coalition_info = NULL;
138
139 (*psattrp)->psa_persona_info = NULL;
140
141 (*psattrp)->psa_posix_cred_info = NULL;
142
143 /*
144 * old coalition field
145 * For backwards compatibility reasons, we set this to 1
146 * which is the first valid coalition id. This will allow
147 * newer user space code to properly spawn processes on
148 * older kernels
149 * (they will just all end up in the same coalition).
150 */
151 (*psattrp)->psa_reserved = 1;
152
153 /* Default is no new clamp */
154 (*psattrp)->psa_qos_clamp = POSIX_SPAWN_PROC_CLAMP_NONE;
155
156 /* Default is no change to role */
157 (*psattrp)->psa_darwin_role = POSIX_SPAWN_DARWIN_ROLE_NONE;
158
159 (*psattrp)->psa_max_addr = 0;
160 }
161
162 return err;
163 }
164
165
166 /*
167 * posix_spawnattr_destroy
168 *
169 * Description: Destroy a spawn attributes object that was previously
170 * initialized via posix_spawnattr_init() by freeing any
171 * memory associated with it and setting it to an invalid value.
172 *
173 * Parameters: attr The spawn attributes object to be
174 * destroyed.
175 *
176 * Returns: 0 Success
177 *
178 * Notes: The destroyed spawn attribute results in the void * pointer
179 * being set to NULL; subsequent use without reinitialization
180 * will result in explicit program failure (rather than merely
181 * "undefined behaviour").
182 *
183 * NOTIMP: Allowed failures (checking NOT required):
184 * EINVAL The value specified by attr is invalid.
185 */
186 static int posix_spawn_destroyportactions_np(posix_spawnattr_t *);
187 static int posix_spawn_destroycoalition_info_np(posix_spawnattr_t *);
188 static int posix_spawn_destroypersona_info_np(posix_spawnattr_t *);
189 static int posix_spawn_destroyposix_cred_info_np(posix_spawnattr_t *);
190 static int posix_spawn_destroymacpolicy_info_np(posix_spawnattr_t *);
191
192 int
193 posix_spawnattr_destroy(posix_spawnattr_t *attr)
194 {
195 _posix_spawnattr_t psattr;
196
197 if (attr == NULL || *attr == NULL) {
198 return EINVAL;
199 }
200
201 psattr = *(_posix_spawnattr_t *)attr;
202 posix_spawn_destroyportactions_np(attr);
203 posix_spawn_destroycoalition_info_np(attr);
204 posix_spawn_destroypersona_info_np(attr);
205 posix_spawn_destroyposix_cred_info_np(attr);
206 posix_spawn_destroymacpolicy_info_np(attr);
207
208 free(psattr);
209 *attr = NULL;
210
211 return 0;
212 }
213
214
215 /*
216 * posix_spawnattr_setflags
217 *
218 * Description: Set the spawn flags attribute for the spawn attribute object
219 * referred to by 'attr'.
220 *
221 * Parameters: attr The spawn attributes object whose flags
222 * are to be set
223 * flags The flags value to set
224 *
225 * Returns: 0 Success
226 *
227 * NOTIMP: Allowed failures (checking NOT required):
228 * EINVAL The value specified by attr is invalid.
229 * EINVAL The value of the attribute being set is not valid.
230 */
231 int
232 posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags)
233 {
234 _posix_spawnattr_t psattr;
235
236 if (attr == NULL || *attr == NULL) {
237 return EINVAL;
238 }
239
240 psattr = *(_posix_spawnattr_t *)attr;
241 psattr->psa_flags = flags;
242
243 return 0;
244 }
245
246
247 /*
248 * posix_spawnattr_getflags
249 *
250 * Description: Retrieve the spawn attributes flag for the spawn attributes
251 * object referenced by 'attr' and place them in the memory
252 * location referenced by 'flagsp'
253 *
254 * Parameters: attr The spawn attributes object whose flags
255 * are to be retrieved
256 * flagsp A pointer to a short value to receive
257 * the flags
258 *
259 * Returns: 0 Success
260 *
261 * Implicit Returns:
262 * *flagps (modified) The flags value from the spawn
263 * attributes object
264 *
265 * NOTIMP: Allowed failures (checking NOT required):
266 * EINVAL The value specified by attr is invalid.
267 * EINVAL The value of the attribute being set is not valid.
268 */
269 int
270 posix_spawnattr_getflags(const posix_spawnattr_t * __restrict attr,
271 short * __restrict flagsp)
272 {
273 _posix_spawnattr_t psattr;
274
275 if (attr == NULL || *attr == NULL) {
276 return EINVAL;
277 }
278
279 psattr = *(_posix_spawnattr_t *)attr;
280 *flagsp = psattr->psa_flags;
281
282 return 0;
283 }
284
285
286 /*
287 * posix_spawnattr_getsigdefault
288 *
289 * Description: Retrieve the set of signals to be set to default according to
290 * the spawn attribute value referenced by 'attr' and place the
291 * result into the memory containing the sigset_t referenced by
292 * 'sigdefault'
293 *
294 * Parameters: attr The spawn attributes object whose
295 * signal set for default signals is to
296 * be retrieved
297 * sigdefault A pointer to the sigset_t to receive
298 * the signal set
299 *
300 * Returns: 0 Success
301 *
302 * Implicit Returns:
303 * *sigdefault (modified) The signal set of signals to default
304 * from the spawn attributes object
305 */
306 int
307 posix_spawnattr_getsigdefault(const posix_spawnattr_t * __restrict attr,
308 sigset_t * __restrict sigdefault)
309 {
310 _posix_spawnattr_t psattr;
311
312 if (attr == NULL || *attr == NULL) {
313 return EINVAL;
314 }
315
316 psattr = *(_posix_spawnattr_t *)attr;
317 *sigdefault = psattr->psa_sigdefault;
318
319 return 0;
320 }
321
322
323 /*
324 * posix_spawnattr_getpgroup
325 *
326 * Description: Obtain the value of the spawn process group attribute from the
327 * spawn attributes object referenced by 'attr' and place the
328 * results in the memory location referenced by 'pgroup'
329 *
330 * Parameters: attr The spawn attributes object whose
331 * process group information is to be
332 * retrieved
333 * pgroup A pointer to the pid_t to receive the
334 * process group
335 *
336 * Returns: 0 Success
337 *
338 * Implicit Returns:
339 * *pgroup (modified) The process group information from the
340 * spawn attributes object
341 */
342 int
343 posix_spawnattr_getpgroup(const posix_spawnattr_t * __restrict attr,
344 pid_t * __restrict pgroup)
345 {
346 _posix_spawnattr_t psattr;
347
348 if (attr == NULL || *attr == NULL) {
349 return EINVAL;
350 }
351
352 psattr = *(_posix_spawnattr_t *)attr;
353 *pgroup = psattr->psa_pgroup;
354
355 return 0;
356 }
357
358
359 /*
360 * posix_spawnattr_getsigmask
361 *
362 * Description: Obtain the value of the spawn signal mask attribute from the
363 * spawn attributes object referenced by 'attr' and place the
364 * result into the memory containing the sigset_t referenced by
365 * 'sigmask'
366 *
367 * Parameters: attr The spawn attributes object whose
368 * signal set for masked signals is to
369 * be retrieved
370 * sigmask A pointer to the sigset_t to receive
371 * the signal set
372 *
373 * Returns: 0 Success
374 *
375 * Implicit Returns:
376 * *sigmask (modified) The signal set of signals to mask
377 * from the spawn attributes object
378 */
379 int
380 posix_spawnattr_getsigmask(const posix_spawnattr_t * __restrict attr,
381 sigset_t * __restrict sigmask)
382 {
383 _posix_spawnattr_t psattr;
384
385 if (attr == NULL || *attr == NULL) {
386 return EINVAL;
387 }
388
389 psattr = *(_posix_spawnattr_t *)attr;
390 *sigmask = psattr->psa_sigmask;
391
392 return 0;
393 }
394
395 /*
396 * posix_spawnattr_getbinpref_np
397 *
398 * Description: Obtain the value of the spawn binary preferences attribute from
399 * the spawn attributes object referenced by 'attr' and place the
400 * result into the memory referenced by 'pref'.
401 *
402 * Parameters: attr The spawn attributes object whose
403 * binary preferences are to be retrieved
404 * count The size of the cpu_type_t array
405 * pref An array of cpu types
406 * ocount The actual number copied
407 *
408 * Returns: 0 No binary preferences found
409 * > 0 The number of cpu types (less than
410 * count) copied over from 'attr'.
411 *
412 * Implicit Returns:
413 * *pref (modified) The binary preferences array
414 * from the spawn attributes object
415 */
416 int
417 posix_spawnattr_getbinpref_np(const posix_spawnattr_t * __restrict attr,
418 size_t count, cpu_type_t *pref, size_t * __restrict ocount)
419 {
420 _posix_spawnattr_t psattr;
421 int i = 0;
422
423 if (attr == NULL || *attr == NULL) {
424 return EINVAL;
425 }
426
427 psattr = *(_posix_spawnattr_t *)attr;
428 for (i = 0; i < count && i < 4; i++) {
429 pref[i] = psattr->psa_binprefs[i];
430 }
431
432 if (ocount) {
433 *ocount = i;
434 }
435 return 0;
436 }
437
438
439 /*
440 * posix_spawnattr_getpcontrol_np
441 *
442 * Description: Retrieve the process control property set default according to
443 * the spawn attribute value referenced by 'attr' and place the
444 * result into the memory containing the control referenced by
445 * 'pcontrol'
446 *
447 * Parameters: attr The spawn attributes object whose
448 * signal set for default signals is to
449 * be retrieved
450 * pcontrol A pointer to an int to receive
451 * the process control info
452 *
453 * Returns: 0 Success
454 *
455 * Implicit Returns:
456 * *pcontrol (modified) The signal set of signals to default
457 * from the spawn attributes object
458 */
459 int
460 posix_spawnattr_getpcontrol_np(const posix_spawnattr_t * __restrict attr,
461 int * __restrict pcontrol)
462 {
463 _posix_spawnattr_t psattr;
464
465 if (attr == NULL || *attr == NULL) {
466 return EINVAL;
467 }
468
469 psattr = *(_posix_spawnattr_t *)attr;
470 *pcontrol = psattr->psa_pcontrol;
471
472 return 0;
473 }
474
475 /*
476 * posix_spawnattr_getprocesstype_np
477 *
478 * Description: Retrieve the process specific behaviors and app launch types
479 * spawn attribute value referenced by 'attr' and place the
480 * result into the memory containing the control referenced by
481 * 'proctype'
482 *
483 * Parameters: attr The spawn attributes object whose
484 * signal set for default signals is to
485 * be retrieved
486 * proctype A pointer to an int to receive
487 * the process type info
488 *
489 * Returns: 0 Success
490 *
491 * Implicit Returns:
492 * *proctype (modified) The process type set to value
493 * from the spawn attributes object
494 */
495 int
496 posix_spawnattr_getprocesstype_np(const posix_spawnattr_t * __restrict attr,
497 int * __restrict proctype)
498 {
499 _posix_spawnattr_t psattr;
500
501 if (attr == NULL || *attr == NULL) {
502 return EINVAL;
503 }
504
505 psattr = *(_posix_spawnattr_t *)attr;
506 *proctype = psattr->psa_apptype;
507
508 return 0;
509 }
510 /*
511 * posix_spawnattr_setsigdefault
512 *
513 * Description: Set the set of signals to be set to default for the spawn
514 * attribute value referenced by 'attr' from the memory
515 * containing the sigset_t referenced by 'sigdefault'
516 *
517 * Parameters: attr The spawn attributes object whose
518 * signal set for default signals is to
519 * be set
520 * sigdefault A pointer to the sigset_t from which to
521 * obtain the signal set
522 *
523 * Returns: 0 Success
524 */
525 int
526 posix_spawnattr_setsigdefault(posix_spawnattr_t * __restrict attr,
527 const sigset_t * __restrict sigdefault)
528 {
529 _posix_spawnattr_t psattr;
530
531 if (attr == NULL || *attr == NULL) {
532 return EINVAL;
533 }
534
535 psattr = *(_posix_spawnattr_t *)attr;
536 psattr->psa_sigdefault = *sigdefault;
537
538 return 0;
539 }
540
541
542 /*
543 * posix_spawnattr_setpgroup
544 *
545 * Description: Set the value of the spawn process group attribute for the
546 * spawn attributes object referenced by 'attr' from the value
547 * of 'pgroup'
548 *
549 * Parameters: attr The spawn attributes object for which
550 * the process group information is to be
551 * set
552 * pgroup The process group to set
553 *
554 * Returns: 0 Success
555 */
556 int
557 posix_spawnattr_setpgroup(posix_spawnattr_t * attr, pid_t pgroup)
558 {
559 _posix_spawnattr_t psattr;
560
561 if (attr == NULL || *attr == NULL) {
562 return EINVAL;
563 }
564
565 psattr = *(_posix_spawnattr_t *)attr;
566 psattr->psa_pgroup = pgroup;
567
568 return 0;
569 }
570
571
572 /*
573 * posix_spawnattr_setsigmask
574 *
575 * Description: Set the set of signals to be masked for the spawn attribute
576 * value referenced by 'attr' from the memory containing the
577 * sigset_t referenced by 'sigmask'
578 *
579 * Parameters: attr The spawn attributes object whose
580 * signal set for masked signals is to
581 * be set
582 * sigmask A pointer to the sigset_t from which to
583 * obtain the signal set
584 *
585 * Returns: 0 Success
586 */
587 int
588 posix_spawnattr_setsigmask(posix_spawnattr_t * __restrict attr,
589 const sigset_t * __restrict sigmask)
590 {
591 _posix_spawnattr_t psattr;
592
593 if (attr == NULL || *attr == NULL) {
594 return EINVAL;
595 }
596
597 psattr = *(_posix_spawnattr_t *)attr;
598 psattr->psa_sigmask = *sigmask;
599
600 return 0;
601 }
602
603
604 /*
605 * posix_spawnattr_setbinpref_np
606 *
607 * Description: Set the universal binary preferences for the spawn attribute
608 * value referenced by 'attr' from the memory containing the
609 * cpu_type_t array referenced by 'pref', size of 'count'
610 *
611 * Parameters: attr The spawn attributes object whose
612 * binary preferences are to be set
613 * count Size of the array pointed to by 'pref'
614 * pref cpu_type_t array of binary preferences
615 * ocount The actual number copied
616 *
617 * Returns: 0 No preferences copied
618 * > 0 Number of preferences copied
619 *
620 * Note: The posix_spawnattr_t currently only holds four cpu_type_t's.
621 * If the caller provides more preferences than this limit, they
622 * will be ignored, as reflected in the return value.
623 */
624 int
625 posix_spawnattr_setbinpref_np(posix_spawnattr_t * __restrict attr,
626 size_t count, cpu_type_t *pref, size_t * __restrict ocount)
627 {
628 _posix_spawnattr_t psattr;
629 int i = 0;
630
631 if (attr == NULL || *attr == NULL) {
632 return EINVAL;
633 }
634
635 psattr = *(_posix_spawnattr_t *)attr;
636 for (i = 0; i < count && i < 4; i++) {
637 psattr->psa_binprefs[i] = pref[i];
638 }
639
640 /* return number of binprefs copied over */
641 if (ocount) {
642 *ocount = i;
643 }
644 return 0;
645 }
646
647
648 /*
649 * posix_spawnattr_setpcontrol_np
650 *
651 * Description: Set the process control property according to
652 * attribute value referenced by 'attr' from the memory
653 * containing the int value 'pcontrol'
654 *
655 * Parameters: attr The spawn attributes object whose
656 * signal set for default signals is to
657 * be set
658 * pcontrol An int value of the process control info
659 *
660 * Returns: 0 Success
661 */
662 int
663 posix_spawnattr_setpcontrol_np(posix_spawnattr_t * __restrict attr,
664 const int pcontrol)
665 {
666 _posix_spawnattr_t psattr;
667
668 if (attr == NULL || *attr == NULL) {
669 return EINVAL;
670 }
671
672 psattr = *(_posix_spawnattr_t *)attr;
673 psattr->psa_pcontrol = pcontrol;
674
675 return 0;
676 }
677
678
679 /*
680 * posix_spawnattr_setprocesstype_np
681 *
682 * Description: Set the process specific behaviors and app launch type
683 * attribute value referenced by 'attr' from the memory
684 * containing the int value 'proctype'
685 *
686 * Parameters: attr The spawn attributes object whose
687 * signal set for default signals is to
688 * be set
689 * proctype An int value of the process type info
690 *
691 * Returns: 0 Success
692 */
693 int
694 posix_spawnattr_setprocesstype_np(posix_spawnattr_t * __restrict attr,
695 const int proctype)
696 {
697 _posix_spawnattr_t psattr;
698
699 if (attr == NULL || *attr == NULL) {
700 return EINVAL;
701 }
702
703 psattr = *(_posix_spawnattr_t *)attr;
704 psattr->psa_apptype = proctype;
705
706 return 0;
707 }
708
709 /*
710 * posix_spawn_createportactions_np
711 * Description: create a new posix_spawn_port_actions struct and link
712 * it into the posix_spawnattr.
713 */
714 static int
715 posix_spawn_createportactions_np(posix_spawnattr_t *attr)
716 {
717 _posix_spawnattr_t psattr;
718 _posix_spawn_port_actions_t acts;
719
720 if (attr == NULL || *attr == NULL) {
721 return EINVAL;
722 }
723
724 psattr = *(_posix_spawnattr_t *)attr;
725 acts = (_posix_spawn_port_actions_t)malloc(PS_PORT_ACTIONS_SIZE(2));
726 if (acts == NULL) {
727 return ENOMEM;
728 }
729
730 acts->pspa_alloc = 2;
731 acts->pspa_count = 0;
732
733 psattr->psa_ports = acts;
734 return 0;
735 }
736
737 /*
738 * posix_spawn_growportactions_np
739 * Description: Enlarge the size of portactions if necessary
740 */
741 static int
742 posix_spawn_growportactions_np(posix_spawnattr_t *attr)
743 {
744 _posix_spawnattr_t psattr;
745 _posix_spawn_port_actions_t acts;
746
747 if (attr == NULL || *attr == NULL) {
748 return EINVAL;
749 }
750
751 psattr = *(_posix_spawnattr_t *)attr;
752 acts = psattr->psa_ports;
753 if (acts == NULL) {
754 return EINVAL;
755 }
756
757 /* Double number of port actions allocated for */
758 int newnum = 0;
759 if (os_mul_overflow(acts->pspa_alloc, 2, &newnum)) {
760 return ENOMEM;
761 }
762 size_t newsize = PS_PORT_ACTIONS_SIZE(newnum);
763 if (newsize == 0) {
764 return ENOMEM;
765 }
766
767 acts = realloc(acts, newsize);
768 if (acts == NULL) {
769 return ENOMEM;
770 }
771
772 acts->pspa_alloc = newnum;
773 psattr->psa_ports = acts;
774 return 0;
775 }
776
777 /*
778 * posix_spawn_destroyportactions_np
779 * Description: clean up portactions struct in posix_spawnattr_t attr
780 */
781 static int
782 posix_spawn_destroyportactions_np(posix_spawnattr_t *attr)
783 {
784 _posix_spawnattr_t psattr;
785 _posix_spawn_port_actions_t acts;
786
787 if (attr == NULL || *attr == NULL) {
788 return EINVAL;
789 }
790
791 psattr = *(_posix_spawnattr_t *)attr;
792 acts = psattr->psa_ports;
793 if (acts == NULL) {
794 return EINVAL;
795 }
796
797 free(acts);
798 return 0;
799 }
800
801 /*
802 * posix_spawn_destroycoalition_info_np
803 * Description: clean up coalition_info struct in posix_spawnattr_t attr
804 */
805 static int
806 posix_spawn_destroycoalition_info_np(posix_spawnattr_t *attr)
807 {
808 _posix_spawnattr_t psattr;
809 struct _posix_spawn_coalition_info *coal_info;
810
811 if (attr == NULL || *attr == NULL) {
812 return EINVAL;
813 }
814
815 psattr = *(_posix_spawnattr_t *)attr;
816 coal_info = psattr->psa_coalition_info;
817 if (coal_info == NULL) {
818 return EINVAL;
819 }
820
821 psattr->psa_coalition_info = NULL;
822 free(coal_info);
823 return 0;
824 }
825
826 /*
827 * posix_spawn_destroypersona_info_np
828 * Description: clean up persona_info struct in posix_spawnattr_t attr
829 */
830 static int
831 posix_spawn_destroypersona_info_np(posix_spawnattr_t *attr)
832 {
833 _posix_spawnattr_t psattr;
834 struct _posix_spawn_persona_info *persona;
835
836 if (attr == NULL || *attr == NULL) {
837 return EINVAL;
838 }
839
840 psattr = *(_posix_spawnattr_t *)attr;
841 persona = psattr->psa_persona_info;
842 if (persona == NULL) {
843 return EINVAL;
844 }
845
846 psattr->psa_persona_info = NULL;
847 free(persona);
848 return 0;
849 }
850
851 /*
852 * posix_spawn_destroyposix_cred_info_np
853 * Description: clean up posix_cred_info struct in posix_spawnattr_t attr
854 */
855 static int
856 posix_spawn_destroyposix_cred_info_np(posix_spawnattr_t *attr)
857 {
858 _posix_spawnattr_t psattr;
859 struct _posix_spawn_posix_cred_info *pspci;
860
861 if (attr == NULL || *attr == NULL) {
862 return EINVAL;
863 }
864
865 psattr = *(_posix_spawnattr_t *)attr;
866 pspci = psattr->psa_posix_cred_info;
867 if (pspci == NULL) {
868 return EINVAL;
869 }
870
871 psattr->psa_posix_cred_info = NULL;
872 free(pspci);
873 return 0;
874 }
875
876 /*
877 * posix_spawn_appendportaction_np
878 * Description: append a port action, grow the array if necessary
879 */
880 static int
881 posix_spawn_appendportaction_np(posix_spawnattr_t *attr, _ps_port_action_t *act)
882 {
883 _posix_spawnattr_t psattr;
884 _posix_spawn_port_actions_t acts;
885
886 if (attr == NULL || *attr == NULL || act == NULL) {
887 return EINVAL;
888 }
889
890 psattr = *(_posix_spawnattr_t *)attr;
891 acts = psattr->psa_ports;
892
893 // Have any port actions been created yet?
894 if (acts == NULL) {
895 int err = posix_spawn_createportactions_np(attr);
896 if (err) {
897 return err;
898 }
899 acts = psattr->psa_ports;
900 }
901
902 // Is there enough room?
903 if (acts->pspa_alloc == acts->pspa_count) {
904 int err = posix_spawn_growportactions_np(attr);
905 if (err) {
906 return err;
907 }
908 acts = psattr->psa_ports;
909 }
910
911 // Add this action to next spot in array
912 acts->pspa_actions[acts->pspa_count] = *act;
913 acts->pspa_count++;
914
915 return 0;
916 }
917
918 /*
919 * posix_spawnattr_setspecialport_np
920 *
921 * Description: Set a new value for a mach special port in the spawned task.
922 *
923 * Parameters: attr The spawn attributes object for the
924 * new process
925 * new_port The new value for the special port
926 * which The particular port to be set
927 * (see task_set_special_port for details)
928 *
929 * Returns: 0 Success
930 * ENOMEM Couldn't allocate memory
931 */
932 int
933 posix_spawnattr_setspecialport_np(
934 posix_spawnattr_t *attr,
935 mach_port_t new_port,
936 int which)
937 {
938 _ps_port_action_t action = {
939 .port_type = PSPA_SPECIAL,
940 .new_port = new_port,
941 .which = which,
942 };
943 return posix_spawn_appendportaction_np(attr, &action);
944 }
945
946 /*
947 * posix_spawnattr_setsuidcredport_np
948 *
949 * Description: Set an suid cred port to be used to execute with a different UID.
950 *
951 * Parameters: attr The spawn attributes object for the
952 * new process
953 * port The suid cred port
954 *
955 * Returns: 0 Success
956 */
957 int
958 posix_spawnattr_setsuidcredport_np(posix_spawnattr_t *attr, mach_port_t port)
959 {
960 _ps_port_action_t action = {
961 .port_type = PSPA_SUID_CRED,
962 .new_port = port,
963 };
964 return posix_spawn_appendportaction_np(attr, &action);
965 }
966
967 /*
968 * posix_spawnattr_setexceptionports_np
969 *
970 * Description: Set a new port for a set of exception ports in the spawned task.
971 *
972 * Parameters: attr The spawn attributes object for the
973 * new process
974 * mask A bitfield indicating which exceptions
975 * to associate the port with
976 * new_port The new value for the exception port
977 * behavior The default behavior for the port
978 * flavor The default flavor for the port
979 * (see task_set_exception_ports)
980 *
981 * Returns: 0 Success
982 */
983 int
984 posix_spawnattr_setexceptionports_np(
985 posix_spawnattr_t *attr,
986 exception_mask_t mask,
987 mach_port_t new_port,
988 exception_behavior_t behavior,
989 thread_state_flavor_t flavor)
990 {
991 _ps_port_action_t action = {
992 .port_type = PSPA_EXCEPTION,
993 .mask = mask,
994 .new_port = new_port,
995 .behavior = behavior,
996 .flavor = flavor,
997 };
998 return posix_spawn_appendportaction_np(attr, &action);
999 }
1000
1001 /*
1002 * posix_spawnattr_setauditsessionport_np
1003 *
1004 * Description: Set the audit session port rights attribute in the spawned task.
1005 * This is used to securely set the audit session information for
1006 * the new task.
1007 *
1008 * Parameters: attr The spawn attributes object for the
1009 * new process
1010 * au_sessionport The audit session send port right
1011 *
1012 * Returns: 0 Success
1013 */
1014 int
1015 posix_spawnattr_setauditsessionport_np(
1016 posix_spawnattr_t *attr,
1017 mach_port_t au_sessionport)
1018 {
1019 _ps_port_action_t action = {
1020 .port_type = PSPA_AU_SESSION,
1021 .new_port = au_sessionport,
1022 };
1023 return posix_spawn_appendportaction_np(attr, &action);
1024 }
1025
1026
1027 /*
1028 * posix_spawn_file_actions_init
1029 *
1030 * Description: Initialize a spawn file actions object attr with default values
1031 *
1032 * Parameters: file_actions The spawn file actions object to be
1033 * initialized
1034 *
1035 * Returns: 0 Success
1036 * ENOMEM Insufficient memory exists to
1037 * initialize the spawn file actions
1038 * object.
1039 *
1040 * Note: As an implementation detail, the externally visibily type
1041 * posix_spawn_file_actions_t is defined to be a void *, and
1042 * initialization involves allocation of a memory object.
1043 * Subsequent changes to the spawn file actions may result in
1044 * reallocation under the covers.
1045 *
1046 * Reinitialization of an already initialized spawn file actions
1047 * object will result in memory being leaked. Because spawn
1048 * file actions are not required to be used in conjunction with a
1049 * static initializer, there is no way to distinguish a spawn
1050 * file actions with stack garbage from one that's been
1051 * initialized. This is arguably an API design error.
1052 */
1053 int
1054 posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions)
1055 {
1056 _posix_spawn_file_actions_t *psactsp = (_posix_spawn_file_actions_t *)file_actions;
1057 int err = 0;
1058
1059 if ((*psactsp = (_posix_spawn_file_actions_t)malloc(PSF_ACTIONS_SIZE(PSF_ACTIONS_INIT_COUNT))) == NULL) {
1060 err = ENOMEM;
1061 } else {
1062 (*psactsp)->psfa_act_alloc = PSF_ACTIONS_INIT_COUNT;
1063 (*psactsp)->psfa_act_count = 0;
1064 }
1065
1066 return err;
1067 }
1068
1069
1070 /*
1071 * posix_spawn_file_actions_destroy
1072 *
1073 * Description: Destroy a spawn file actions object that was previously
1074 * initialized via posix_spawn_file_actions_init() by freeing any
1075 * memory associated with it and setting it to an invalid value.
1076 *
1077 * Parameters: attr The spawn file actions object to be
1078 * destroyed.
1079 *
1080 * Returns: 0 Success
1081 *
1082 * Notes: The destroyed spawn file actions results in the void * pointer
1083 * being set to NULL; subsequent use without reinitialization
1084 * will result in explicit program failure (rather than merely
1085 * "undefined behaviour").
1086 *
1087 * NOTIMP: Allowed failures (checking NOT required):
1088 * EINVAL The value specified by file_actions is invalid.
1089 */
1090 int
1091 posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions)
1092 {
1093 _posix_spawn_file_actions_t psacts;
1094
1095 if (file_actions == NULL || *file_actions == NULL) {
1096 return EINVAL;
1097 }
1098
1099 psacts = *(_posix_spawn_file_actions_t *)file_actions;
1100 free(psacts);
1101 *file_actions = NULL;
1102
1103 return 0;
1104 }
1105
1106
1107 /*
1108 * _posix_spawn_file_actions_grow
1109 *
1110 * Description: Grow the available list of file actions associated with the
1111 * pointer to the structure provided; replace the contents of the
1112 * pointer as a side effect.
1113 *
1114 * Parameters: psactsp Pointer to _posix_spawn_file_actions_t
1115 * to grow
1116 *
1117 * Returns: 0 Success
1118 * ENOMEM Insufficient memory for operation
1119 *
1120 * Notes: This code is common to all posix_spawn_file_actions_*()
1121 * functions, since we use a naieve data structure implementation
1122 * at present. Future optimization will likely change this.
1123 */
1124 static int
1125 _posix_spawn_file_actions_grow(_posix_spawn_file_actions_t *psactsp)
1126 {
1127 int newnum = 0;
1128 if (os_mul_overflow((*psactsp)->psfa_act_alloc, 2, &newnum)) {
1129 return ENOMEM;
1130 }
1131
1132 size_t newsize = PSF_ACTIONS_SIZE(newnum);
1133 if (newsize == 0) {
1134 return ENOMEM;
1135 }
1136
1137 /*
1138 * XXX may want to impose an administrative limit here; POSIX does
1139 * XXX not provide for an administrative error return in this case,
1140 * XXX so it's probably acceptable to just fail catastrophically
1141 * XXX instead of implementing one.
1142 */
1143 _posix_spawn_file_actions_t new_psacts;
1144 if ((new_psacts = (_posix_spawn_file_actions_t)realloc((*psactsp), newsize)) == NULL) {
1145 return ENOMEM;
1146 }
1147 new_psacts->psfa_act_alloc = newnum;
1148 *psactsp = new_psacts;
1149
1150 return 0;
1151 }
1152
1153
1154 /*
1155 * posix_spawn_file_actions_addopen
1156 *
1157 * Description: Add an open action to the object referenced by 'file_actions'
1158 * that will cause the file named by 'path' to be attempted to be
1159 * opened with flags 'oflag' and mode 'mode', and, if successful,
1160 * return as descriptor 'filedes' to the spawned process.
1161 *
1162 * Parameters: file_actions File action object to augment
1163 * filedes fd that open is to use
1164 * path path to file to open
1165 * oflag open file flags
1166 * mode open file mode
1167 *
1168 * Returns: 0 Success
1169 * EBADF The value specified by fildes is
1170 * negative or greater than or equal to
1171 * {OPEN_MAX}.
1172 * ENOMEM Insufficient memory exists to add to
1173 * the spawn file actions object.
1174 *
1175 * NOTIMP: Allowed failures (checking NOT required):
1176 * EINVAL The value specified by file_actions is invalid.
1177 */
1178 int
1179 posix_spawn_file_actions_addopen(
1180 posix_spawn_file_actions_t * __restrict file_actions,
1181 int filedes, const char * __restrict path, int oflag,
1182 mode_t mode)
1183 {
1184 _posix_spawn_file_actions_t *psactsp;
1185 _psfa_action_t *psfileact;
1186
1187 if (file_actions == NULL || *file_actions == NULL) {
1188 return EINVAL;
1189 }
1190
1191 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1192 /* Range check; required by POSIX */
1193 if (filedes < 0 || filedes >= OPEN_MAX) {
1194 return EBADF;
1195 }
1196
1197 /* If we do not have enough slots, grow the structure */
1198 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1199 /* need to grow file actions structure */
1200 if (_posix_spawn_file_actions_grow(psactsp)) {
1201 return ENOMEM;
1202 }
1203 }
1204
1205 /*
1206 * Allocate next available slot and fill it out
1207 */
1208 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1209
1210 psfileact->psfaa_type = PSFA_OPEN;
1211 psfileact->psfaa_filedes = filedes;
1212 psfileact->psfaa_openargs.psfao_oflag = oflag;
1213 psfileact->psfaa_openargs.psfao_mode = mode;
1214 strlcpy(psfileact->psfaa_openargs.psfao_path, path, PATH_MAX);
1215
1216 return 0;
1217 }
1218
1219
1220 /*
1221 * posix_spawn_file_actions_addclose
1222 *
1223 * Description: Add a close action to the object referenced by 'file_actions'
1224 * that will cause the file referenced by 'filedes' to be
1225 * attempted to be closed in the spawned process.
1226 *
1227 * Parameters: file_actions File action object to augment
1228 * filedes fd to close
1229 *
1230 * Returns: 0 Success
1231 * EBADF The value specified by fildes is
1232 * negative or greater than or equal to
1233 * {OPEN_MAX}.
1234 * ENOMEM Insufficient memory exists to add to
1235 * the spawn file actions object.
1236 *
1237 * NOTIMP: Allowed failures (checking NOT required):
1238 * EINVAL The value specified by file_actions is invalid.
1239 */
1240 int
1241 posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions,
1242 int filedes)
1243 {
1244 _posix_spawn_file_actions_t *psactsp;
1245 _psfa_action_t *psfileact;
1246
1247 if (file_actions == NULL || *file_actions == NULL) {
1248 return EINVAL;
1249 }
1250
1251 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1252 /* Range check; required by POSIX */
1253 if (filedes < 0 || filedes >= OPEN_MAX) {
1254 return EBADF;
1255 }
1256
1257 /* If we do not have enough slots, grow the structure */
1258 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1259 /* need to grow file actions structure */
1260 if (_posix_spawn_file_actions_grow(psactsp)) {
1261 return ENOMEM;
1262 }
1263 }
1264
1265 /*
1266 * Allocate next available slot and fill it out
1267 */
1268 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1269
1270 psfileact->psfaa_type = PSFA_CLOSE;
1271 psfileact->psfaa_filedes = filedes;
1272
1273 return 0;
1274 }
1275
1276
1277 /*
1278 * posix_spawn_file_actions_adddup2
1279 *
1280 * Description: Add a dup2 action to the object referenced by 'file_actions'
1281 * that will cause the file referenced by 'filedes' to be
1282 * attempted to be dup2'ed to the descriptor 'newfiledes' in the
1283 * spawned process.
1284 *
1285 * Parameters: file_actions File action object to augment
1286 * filedes fd to dup2
1287 * newfiledes fd to dup2 it to
1288 *
1289 * Returns: 0 Success
1290 * EBADF The value specified by either fildes
1291 * or by newfiledes is negative or greater
1292 * than or equal to {OPEN_MAX}.
1293 * ENOMEM Insufficient memory exists to add to
1294 * the spawn file actions object.
1295 *
1296 * NOTIMP: Allowed failures (checking NOT required):
1297 * EINVAL The value specified by file_actions is invalid.
1298 */
1299 int
1300 posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions,
1301 int filedes, int newfiledes)
1302 {
1303 _posix_spawn_file_actions_t *psactsp;
1304 _psfa_action_t *psfileact;
1305
1306 if (file_actions == NULL || *file_actions == NULL) {
1307 return EINVAL;
1308 }
1309
1310 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1311 /* Range check; required by POSIX */
1312 if (filedes < 0 || filedes >= OPEN_MAX ||
1313 newfiledes < 0 || newfiledes >= OPEN_MAX) {
1314 return EBADF;
1315 }
1316
1317 /* If we do not have enough slots, grow the structure */
1318 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1319 /* need to grow file actions structure */
1320 if (_posix_spawn_file_actions_grow(psactsp)) {
1321 return ENOMEM;
1322 }
1323 }
1324
1325 /*
1326 * Allocate next available slot and fill it out
1327 */
1328 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1329
1330 psfileact->psfaa_type = PSFA_DUP2;
1331 psfileact->psfaa_filedes = filedes;
1332 psfileact->psfaa_dup2args.psfad_newfiledes = newfiledes;
1333
1334 return 0;
1335 }
1336
1337 /*
1338 * posix_spawn_file_actions_add_fileportdup2_np
1339 *
1340 * Description: Add a dup2 action to the object referenced by 'file_actions'
1341 * that will cause the file referenced by 'fileport' to be
1342 * attempted to be dup2'ed to the descriptor 'newfiledes' in the
1343 * spawned process.
1344 *
1345 * Parameters: file_actions File action object to augment
1346 * filedes fileport to dup2
1347 * newfiledes fd to dup2 it to
1348 *
1349 * Returns: 0 Success
1350 * EBADF fileport isn't a valid port, or the
1351 * value specified by newfiledes is
1352 * negative or greater than or equal to
1353 * {OPEN_MAX}.
1354 * ENOMEM Insufficient memory exists to add to
1355 * the spawn file actions object.
1356 *
1357 * NOTIMP: Allowed failures (checking NOT required):
1358 * EINVAL The value specified by file_actions is invalid.
1359 */
1360 int
1361 posix_spawn_file_actions_add_fileportdup2_np(
1362 posix_spawn_file_actions_t *file_actions,
1363 mach_port_t fileport, int newfiledes)
1364 {
1365 _posix_spawn_file_actions_t *psactsp;
1366 _psfa_action_t *psfileact;
1367
1368 if (file_actions == NULL || *file_actions == NULL) {
1369 return EINVAL;
1370 }
1371
1372 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1373 /* Range check; required by POSIX */
1374 if (!MACH_PORT_VALID(fileport) ||
1375 newfiledes < 0 || newfiledes >= OPEN_MAX) {
1376 return EBADF;
1377 }
1378
1379 /* If we do not have enough slots, grow the structure */
1380 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1381 /* need to grow file actions structure */
1382 if (_posix_spawn_file_actions_grow(psactsp)) {
1383 return ENOMEM;
1384 }
1385 }
1386
1387 /*
1388 * Allocate next available slot and fill it out
1389 */
1390 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1391
1392 psfileact->psfaa_type = PSFA_FILEPORT_DUP2;
1393 psfileact->psfaa_fileport = fileport;
1394 psfileact->psfaa_dup2args.psfad_newfiledes = newfiledes;
1395
1396 return 0;
1397 }
1398
1399 /*
1400 * posix_spawn_file_actions_addinherit_np
1401 *
1402 * Description: Add the "inherit" action to the object referenced by
1403 * 'file_actions' that will cause the file referenced by
1404 * 'filedes' to continue to be available in the spawned
1405 * process via the same descriptor.
1406 *
1407 * Inheritance is the normal default behaviour for
1408 * file descriptors across exec and spawn; but if the
1409 * POSIX_SPAWN_CLOEXEC_DEFAULT flag is set, the usual
1410 * default is reversed for the purposes of the spawn
1411 * invocation. Any pre-existing descriptors that
1412 * need to be made available to the spawned process can
1413 * be marked explicitly as 'inherit' via this interface.
1414 * Otherwise they will be automatically closed.
1415 *
1416 * Note that any descriptors created via the other file
1417 * actions interfaces are automatically marked as 'inherit'.
1418 *
1419 * Parameters: file_actions File action object to augment
1420 * filedes fd to inherit.
1421 *
1422 * Returns: 0 Success
1423 * EBADF The value specified by fildes is
1424 * negative or greater than or equal to
1425 * {OPEN_MAX}.
1426 * ENOMEM Insufficient memory exists to add to
1427 * the spawn file actions object.
1428 *
1429 * NOTIMP: Allowed failures (checking NOT required):
1430 * EINVAL The value specified by file_actions is invalid.
1431 */
1432 int
1433 posix_spawn_file_actions_addinherit_np(posix_spawn_file_actions_t *file_actions,
1434 int filedes)
1435 {
1436 _posix_spawn_file_actions_t *psactsp;
1437 _psfa_action_t *psfileact;
1438
1439 if (file_actions == NULL || *file_actions == NULL) {
1440 return EINVAL;
1441 }
1442
1443 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1444 /* Range check; required by POSIX */
1445 if (filedes < 0 || filedes >= OPEN_MAX) {
1446 return EBADF;
1447 }
1448
1449 #if defined(POSIX_SPAWN_CLOEXEC_DEFAULT) // TODO: delete this check
1450 /* If we do not have enough slots, grow the structure */
1451 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1452 /* need to grow file actions structure */
1453 if (_posix_spawn_file_actions_grow(psactsp)) {
1454 return ENOMEM;
1455 }
1456 }
1457
1458 /*
1459 * Allocate next available slot and fill it out
1460 */
1461 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1462
1463 psfileact->psfaa_type = PSFA_INHERIT;
1464 psfileact->psfaa_filedes = filedes;
1465 #endif
1466 return 0;
1467 }
1468
1469
1470 /*
1471 * posix_spawn_file_actions_addchdir_np
1472 *
1473 * Description: Add a chdir action to the object referenced by 'file_actions'
1474 * that will cause the current working directory to attempt to be changed
1475 * to that referenced by 'path' in the spawned process.
1476 *
1477 * Parameters: file_actions File action object to augment
1478 * path path of the desired working directory
1479 *
1480 * Returns: 0 Success
1481 * ENOMEM Insufficient memory exists to add to
1482 * the spawn file actions object.
1483 * ENAMETOOLONG The supplied path exceeded PATH_MAX.
1484 *
1485 * NOTIMP: Allowed failures (checking NOT required):
1486 * EINVAL The value specified by file_actions is invalid.
1487 */
1488 int
1489 posix_spawn_file_actions_addchdir_np(
1490 posix_spawn_file_actions_t * __restrict file_actions,
1491 const char * __restrict path)
1492 {
1493 _posix_spawn_file_actions_t *psactsp;
1494 _psfa_action_t *psfileact;
1495
1496 if (file_actions == NULL || *file_actions == NULL) {
1497 return EINVAL;
1498 }
1499
1500 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1501
1502 /* If we do not have enough slots, grow the structure */
1503 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1504 /* need to grow file actions structure */
1505 if (_posix_spawn_file_actions_grow(psactsp)) {
1506 return ENOMEM;
1507 }
1508 }
1509
1510 /*
1511 * Allocate next available slot and fill it out
1512 */
1513 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1514
1515 psfileact->psfaa_type = PSFA_CHDIR;
1516 if (strlcpy(psfileact->psfaa_chdirargs.psfac_path, path, PATH_MAX) >= PATH_MAX) {
1517 (*psactsp)->psfa_act_count--;
1518 return ENAMETOOLONG;
1519 }
1520
1521 return 0;
1522 }
1523
1524
1525 /*
1526 * posix_spawn_file_actions_fchdir_np
1527 *
1528 * Description: Add a fchdir action to the object referenced by 'file_actions'
1529 * that will cause the current working directory to attempt to be changed
1530 * to that referenced by the descriptor 'filedes' in the spawned process.
1531 *
1532 * Parameters: file_actions File action object to augment
1533 * filedes fd to chdir to
1534 *
1535 * Returns: 0 Success
1536 * EBADF The value specified by either fildes is negative or
1537 * greater than or equal to {OPEN_MAX}.
1538 * ENOMEM Insufficient memory exists to add to
1539 * the spawn file actions object.
1540 *
1541 * NOTIMP: Allowed failures (checking NOT required):
1542 * EINVAL The value specified by file_actions is invalid.
1543 */
1544 int
1545 posix_spawn_file_actions_addfchdir_np(posix_spawn_file_actions_t *file_actions,
1546 int filedes)
1547 {
1548 _posix_spawn_file_actions_t *psactsp;
1549 _psfa_action_t *psfileact;
1550
1551 if (file_actions == NULL || *file_actions == NULL) {
1552 return EINVAL;
1553 }
1554
1555 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1556 /* Range check; in spirit of POSIX */
1557 if (filedes < 0 || filedes >= OPEN_MAX) {
1558 return EBADF;
1559 }
1560
1561 /* If we do not have enough slots, grow the structure */
1562 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1563 /* need to grow file actions structure */
1564 if (_posix_spawn_file_actions_grow(psactsp)) {
1565 return ENOMEM;
1566 }
1567 }
1568
1569 /*
1570 * Allocate next available slot and fill it out
1571 */
1572 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1573
1574 psfileact->psfaa_type = PSFA_FCHDIR;
1575 psfileact->psfaa_filedes = filedes;
1576
1577 return 0;
1578 }
1579
1580 int
1581 posix_spawnattr_setcpumonitor_default(posix_spawnattr_t * __restrict attr)
1582 {
1583 return posix_spawnattr_setcpumonitor(attr, PROC_POLICY_CPUMON_DEFAULTS, 0);
1584 }
1585
1586 int
1587 posix_spawnattr_setcpumonitor(posix_spawnattr_t * __restrict attr,
1588 uint64_t percent, uint64_t interval)
1589 {
1590 _posix_spawnattr_t psattr;
1591
1592 if (attr == NULL || *attr == NULL) {
1593 return EINVAL;
1594 }
1595
1596 psattr = *(_posix_spawnattr_t *)attr;
1597
1598 psattr->psa_cpumonitor_percent = percent;
1599 psattr->psa_cpumonitor_interval = interval;
1600
1601 return 0;
1602 }
1603
1604 int
1605 posix_spawnattr_getcpumonitor(posix_spawnattr_t * __restrict attr,
1606 uint64_t *percent, uint64_t *interval)
1607 {
1608 _posix_spawnattr_t psattr;
1609
1610 if (attr == NULL || *attr == NULL) {
1611 return EINVAL;
1612 }
1613
1614 psattr = *(_posix_spawnattr_t *)attr;
1615
1616 *percent = psattr->psa_cpumonitor_percent;
1617 *interval = psattr->psa_cpumonitor_interval;
1618
1619 return 0;
1620 }
1621
1622 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
1623 /*
1624 * posix_spawnattr_setjetsam
1625 *
1626 * Description: Set jetsam attributes for the spawn attribute object
1627 * referred to by 'attr'.
1628 *
1629 * Parameters: flags The flags value to set
1630 * priority Relative jetsam priority
1631 * memlimit Value in megabytes; a memory footprint
1632 * above this level may result in termination.
1633 * Implies both active and inactive limits.
1634 *
1635 * Returns: 0 Success
1636 *
1637 * Note: to be deprecated (not available on desktop)
1638 *
1639 */
1640 int
1641 posix_spawnattr_setjetsam(posix_spawnattr_t * __restrict attr,
1642 short flags, int priority, int memlimit)
1643 {
1644 short flags_ext = flags;
1645
1646 if (flags & POSIX_SPAWN_JETSAM_MEMLIMIT_FATAL) {
1647 flags_ext |= POSIX_SPAWN_JETSAM_MEMLIMIT_ACTIVE_FATAL;
1648 flags_ext |= POSIX_SPAWN_JETSAM_MEMLIMIT_INACTIVE_FATAL;
1649 } else {
1650 flags_ext &= ~POSIX_SPAWN_JETSAM_MEMLIMIT_ACTIVE_FATAL;
1651 flags_ext &= ~POSIX_SPAWN_JETSAM_MEMLIMIT_INACTIVE_FATAL;
1652 }
1653
1654 return posix_spawnattr_setjetsam_ext(attr, flags_ext, priority, memlimit, memlimit);
1655 }
1656 #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
1657
1658 /*
1659 * posix_spawnattr_setjetsam_ext
1660 *
1661 * Description: Set jetsam attributes for the spawn attribute object
1662 * referred to by 'attr'.
1663 *
1664 * Parameters: flags The flags value to set
1665 * priority Relative jetsam priority
1666 * memlimit_active Value in megabytes; memory footprint
1667 * above this level while process is
1668 * active may result in termination.
1669 * memlimit_inactive Value in megabytes; memory footprint
1670 * above this level while process is
1671 * inactive may result in termination.
1672 *
1673 * Returns: 0 Success
1674 */
1675 int
1676 posix_spawnattr_setjetsam_ext(posix_spawnattr_t * __restrict attr,
1677 short flags, int priority, int memlimit_active, int memlimit_inactive)
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
1687 psattr->psa_jetsam_flags = flags;
1688 psattr->psa_jetsam_flags |= POSIX_SPAWN_JETSAM_SET;
1689 psattr->psa_priority = priority;
1690 psattr->psa_memlimit_active = memlimit_active;
1691 psattr->psa_memlimit_inactive = memlimit_inactive;
1692
1693 return 0;
1694 }
1695
1696 int
1697 posix_spawnattr_set_threadlimit_ext(posix_spawnattr_t * __restrict attr,
1698 int thread_limit)
1699 {
1700 _posix_spawnattr_t psattr;
1701
1702 if (attr == NULL || *attr == NULL) {
1703 return EINVAL;
1704 }
1705
1706 psattr = *(_posix_spawnattr_t *)attr;
1707
1708 psattr->psa_thread_limit = thread_limit;
1709
1710 return 0;
1711 }
1712
1713
1714 /*
1715 * posix_spawnattr_set_importancewatch_port_np
1716 *
1717 * Description: Mark ports referred to by these rights
1718 * to boost the new task instead of their current task
1719 * for the spawn attribute object referred to by 'attr'.
1720 * Ports must be valid at posix_spawn time. They will NOT be
1721 * consumed by the kernel, so they must be deallocated after the spawn returns.
1722 * (If you are SETEXEC-ing, they are cleaned up by the exec operation).
1723 *
1724 * The maximum number of watch ports allowed is defined by POSIX_SPAWN_IMPORTANCE_PORT_COUNT.
1725 *
1726 * Parameters: count Number of ports in portarray
1727 * portarray Array of rights
1728 *
1729 * Returns: 0 Success
1730 * EINVAL Bad port count
1731 * ENOMEM Insufficient memory exists to add to
1732 * the spawn port actions object.
1733 */
1734 int
1735 posix_spawnattr_set_importancewatch_port_np(posix_spawnattr_t * __restrict attr,
1736 int count, mach_port_t portarray[])
1737 {
1738 int err = 0, i;
1739
1740 if (count < 0 || count > POSIX_SPAWN_IMPORTANCE_PORT_COUNT) {
1741 return EINVAL;
1742 }
1743
1744 for (i = 0; i < count; i++) {
1745 _ps_port_action_t action = {
1746 .port_type = PSPA_IMP_WATCHPORTS,
1747 .new_port = portarray[i],
1748 };
1749 err = posix_spawn_appendportaction_np(attr, &action);
1750 if (err) {
1751 break;
1752 }
1753 }
1754 return err;
1755 }
1756
1757 int
1758 posix_spawnattr_set_registered_ports_np(posix_spawnattr_t * __restrict attr,
1759 mach_port_t portarray[], uint32_t count)
1760 {
1761 int err = 0;
1762
1763 if (count > TASK_PORT_REGISTER_MAX) {
1764 return EINVAL;
1765 }
1766
1767 for (uint32_t i = 0; i < count; i++) {
1768 _ps_port_action_t action = {
1769 .port_type = PSPA_REGISTERED_PORTS,
1770 .new_port = portarray[i],
1771 };
1772 err = posix_spawn_appendportaction_np(attr, &action);
1773 if (err) {
1774 break;
1775 }
1776 }
1777 return err;
1778 }
1779
1780
1781 static
1782 _ps_mac_policy_extension_t *
1783 posix_spawnattr_macpolicyinfo_lookup(_posix_spawn_mac_policy_extensions_t psmx, const char *policyname)
1784 {
1785 int i;
1786
1787 if (psmx == NULL) {
1788 return NULL;
1789 }
1790
1791 for (i = 0; i < psmx->psmx_count; i++) {
1792 _ps_mac_policy_extension_t *extension = &psmx->psmx_extensions[i];
1793 if (strcmp(extension->policyname, policyname) == 0) {
1794 return extension;
1795 }
1796 }
1797 return NULL;
1798 }
1799
1800 int
1801 posix_spawnattr_getmacpolicyinfo_np(const posix_spawnattr_t * __restrict attr,
1802 const char *policyname, void **datap, size_t *datalenp)
1803 {
1804 _posix_spawnattr_t psattr;
1805 _ps_mac_policy_extension_t *extension;
1806
1807 if (attr == NULL || *attr == NULL || policyname == NULL || datap == NULL) {
1808 return EINVAL;
1809 }
1810
1811 psattr = *(_posix_spawnattr_t *)attr;
1812 extension = posix_spawnattr_macpolicyinfo_lookup(psattr->psa_mac_extensions, policyname);
1813 if (extension == NULL) {
1814 return ESRCH;
1815 }
1816 *datap = (void *)(uintptr_t)extension->data;
1817 if (datalenp != NULL) {
1818 *datalenp = (size_t)extension->datalen;
1819 }
1820 return 0;
1821 }
1822
1823 int
1824 posix_spawnattr_setmacpolicyinfo_np(posix_spawnattr_t * __restrict attr,
1825 const char *policyname, void *data, size_t datalen)
1826 {
1827 _posix_spawnattr_t psattr;
1828 _posix_spawn_mac_policy_extensions_t psmx;
1829 _ps_mac_policy_extension_t *extension;
1830
1831 if (attr == NULL || *attr == NULL || policyname == NULL) {
1832 return EINVAL;
1833 }
1834
1835 psattr = *(_posix_spawnattr_t *)attr;
1836 psmx = psattr->psa_mac_extensions;
1837 extension = posix_spawnattr_macpolicyinfo_lookup(psattr->psa_mac_extensions, policyname);
1838 if (extension != NULL) {
1839 extension->data = (uintptr_t)data;
1840 extension->datalen = datalen;
1841 return 0;
1842 } else if (psmx == NULL) {
1843 psmx = psattr->psa_mac_extensions = malloc(PS_MAC_EXTENSIONS_SIZE(PS_MAC_EXTENSIONS_INIT_COUNT));
1844 if (psmx == NULL) {
1845 return ENOMEM;
1846 }
1847 psmx->psmx_alloc = PS_MAC_EXTENSIONS_INIT_COUNT;
1848 psmx->psmx_count = 0;
1849 } else if (psmx->psmx_count == psmx->psmx_alloc) {
1850 int newnum = 0;
1851 if (os_mul_overflow(psmx->psmx_alloc, 2, &newnum)) {
1852 return ENOMEM;
1853 }
1854 size_t extsize = PS_MAC_EXTENSIONS_SIZE(newnum);
1855 if (extsize == 0) {
1856 return ENOMEM;
1857 }
1858 psmx = psattr->psa_mac_extensions = reallocf(psmx, extsize);
1859 if (psmx == NULL) {
1860 return ENOMEM;
1861 }
1862 psmx->psmx_alloc = newnum;
1863 }
1864 extension = &psmx->psmx_extensions[psmx->psmx_count];
1865 strlcpy(extension->policyname, policyname, sizeof(extension->policyname));
1866 extension->data = (uintptr_t)data;
1867 extension->datalen = datalen;
1868 psmx->psmx_count += 1;
1869 return 0;
1870 }
1871
1872 /*
1873 * posix_spawn_destroymacpolicy_info_np
1874 * Description: cleanup the macpolicy struct in posix_spawnattr_t attr
1875 */
1876 static int
1877 posix_spawn_destroymacpolicy_info_np(posix_spawnattr_t *attr)
1878 {
1879 _posix_spawnattr_t psattr;
1880 _posix_spawn_mac_policy_extensions_t psmx;
1881
1882 if (attr == NULL || *attr == NULL) {
1883 return EINVAL;
1884 }
1885
1886 psattr = *(_posix_spawnattr_t *)attr;
1887 psmx = psattr->psa_mac_extensions;
1888 if (psmx == NULL) {
1889 return EINVAL;
1890 }
1891
1892 psattr->psa_mac_extensions = NULL;
1893 free(psmx);
1894 return 0;
1895 }
1896
1897 int
1898 posix_spawnattr_setcoalition_np(const posix_spawnattr_t * __restrict attr,
1899 uint64_t coalitionid, int type, int role)
1900 {
1901 _posix_spawnattr_t psattr;
1902 struct _posix_spawn_coalition_info *coal_info;
1903
1904 if (attr == NULL || *attr == NULL) {
1905 return EINVAL;
1906 }
1907 if (type < 0 || type > COALITION_TYPE_MAX) {
1908 return EINVAL;
1909 }
1910
1911 psattr = *(_posix_spawnattr_t *)attr;
1912
1913 coal_info = psattr->psa_coalition_info;
1914 if (!coal_info) {
1915 coal_info = (struct _posix_spawn_coalition_info *)malloc(sizeof(*coal_info));
1916 if (!coal_info) {
1917 return ENOMEM;
1918 }
1919 memset(coal_info, 0, sizeof(*coal_info));
1920 psattr->psa_coalition_info = coal_info;
1921 }
1922
1923 coal_info->psci_info[type].psci_id = coalitionid;
1924 coal_info->psci_info[type].psci_role = role;
1925
1926 return 0;
1927 }
1928
1929
1930 int
1931 posix_spawnattr_set_qos_clamp_np(const posix_spawnattr_t * __restrict attr, uint64_t qos_clamp)
1932 {
1933 _posix_spawnattr_t psattr;
1934
1935 if (attr == NULL || *attr == NULL) {
1936 return EINVAL;
1937 }
1938
1939 if (qos_clamp >= POSIX_SPAWN_PROC_CLAMP_LAST) {
1940 return EINVAL;
1941 }
1942
1943 psattr = *(_posix_spawnattr_t *)attr;
1944 psattr->psa_qos_clamp = qos_clamp;
1945
1946 return 0;
1947 }
1948
1949 int
1950 posix_spawnattr_get_qos_clamp_np(const posix_spawnattr_t * __restrict attr, uint64_t * __restrict qos_clampp)
1951 {
1952 _posix_spawnattr_t psattr;
1953
1954 if (attr == NULL || *attr == NULL) {
1955 return EINVAL;
1956 }
1957
1958 psattr = *(_posix_spawnattr_t *)attr;
1959 *qos_clampp = psattr->psa_qos_clamp;
1960
1961 return 0;
1962 }
1963
1964 int
1965 posix_spawnattr_set_darwin_role_np(const posix_spawnattr_t * __restrict attr, uint64_t darwin_role)
1966 {
1967 _posix_spawnattr_t psattr;
1968
1969 if (attr == NULL || *attr == NULL) {
1970 return EINVAL;
1971 }
1972
1973 psattr = *(_posix_spawnattr_t *)attr;
1974 psattr->psa_darwin_role = darwin_role;
1975
1976 return 0;
1977 }
1978
1979 int
1980 posix_spawnattr_get_darwin_role_np(const posix_spawnattr_t * __restrict attr, uint64_t * __restrict darwin_rolep)
1981 {
1982 _posix_spawnattr_t psattr;
1983
1984 if (attr == NULL || *attr == NULL) {
1985 return EINVAL;
1986 }
1987
1988 psattr = *(_posix_spawnattr_t *)attr;
1989 *darwin_rolep = psattr->psa_darwin_role;
1990
1991 return 0;
1992 }
1993
1994
1995 int
1996 posix_spawnattr_set_persona_np(const posix_spawnattr_t * __restrict attr, uid_t persona_id, uint32_t flags)
1997 {
1998 _posix_spawnattr_t psattr;
1999 struct _posix_spawn_persona_info *persona;
2000
2001 if (attr == NULL || *attr == NULL) {
2002 return EINVAL;
2003 }
2004
2005 if (flags & ~POSIX_SPAWN_PERSONA_ALL_FLAGS) {
2006 return EINVAL;
2007 }
2008
2009 psattr = *(_posix_spawnattr_t *)attr;
2010
2011 persona = psattr->psa_persona_info;
2012 if (!persona) {
2013 persona = (struct _posix_spawn_persona_info *)malloc(sizeof(*persona));
2014 if (!persona) {
2015 return ENOMEM;
2016 }
2017 persona->pspi_uid = 0;
2018 persona->pspi_gid = 0;
2019 persona->pspi_ngroups = 0;
2020 persona->pspi_groups[0] = 0;
2021 persona->pspi_gmuid = 0;
2022
2023 psattr->psa_persona_info = persona;
2024 }
2025
2026 persona->pspi_id = persona_id;
2027 persona->pspi_flags = flags;
2028
2029 return 0;
2030 }
2031
2032 int
2033 posix_spawnattr_set_persona_uid_np(const posix_spawnattr_t * __restrict attr, uid_t uid)
2034 {
2035 _posix_spawnattr_t psattr;
2036 struct _posix_spawn_persona_info *persona;
2037
2038 if (attr == NULL || *attr == NULL) {
2039 return EINVAL;
2040 }
2041
2042 psattr = *(_posix_spawnattr_t *)attr;
2043 persona = psattr->psa_persona_info;
2044 if (!persona) {
2045 return EINVAL;
2046 }
2047
2048 if (!(persona->pspi_flags & (POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE | POSIX_SPAWN_PERSONA_FLAGS_VERIFY))) {
2049 return EINVAL;
2050 }
2051
2052 persona->pspi_uid = uid;
2053
2054 persona->pspi_flags |= POSIX_SPAWN_PERSONA_UID;
2055
2056 return 0;
2057 }
2058
2059 int
2060 posix_spawnattr_set_persona_gid_np(const posix_spawnattr_t * __restrict attr, gid_t gid)
2061 {
2062 _posix_spawnattr_t psattr;
2063 struct _posix_spawn_persona_info *persona;
2064
2065 if (attr == NULL || *attr == NULL) {
2066 return EINVAL;
2067 }
2068
2069 psattr = *(_posix_spawnattr_t *)attr;
2070 persona = psattr->psa_persona_info;
2071 if (!persona) {
2072 return EINVAL;
2073 }
2074
2075 if (!(persona->pspi_flags & (POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE | POSIX_SPAWN_PERSONA_FLAGS_VERIFY))) {
2076 return EINVAL;
2077 }
2078
2079 persona->pspi_gid = gid;
2080
2081 persona->pspi_flags |= POSIX_SPAWN_PERSONA_GID;
2082
2083 return 0;
2084 }
2085
2086 int
2087 posix_spawnattr_set_persona_groups_np(const posix_spawnattr_t * __restrict attr, int ngroups, gid_t *gidarray, uid_t gmuid)
2088 {
2089 _posix_spawnattr_t psattr;
2090 struct _posix_spawn_persona_info *persona;
2091
2092 if (attr == NULL || *attr == NULL) {
2093 return EINVAL;
2094 }
2095
2096 if (gidarray == NULL) {
2097 return EINVAL;
2098 }
2099
2100 if (ngroups > NGROUPS || ngroups < 0) {
2101 return EINVAL;
2102 }
2103
2104 psattr = *(_posix_spawnattr_t *)attr;
2105 persona = psattr->psa_persona_info;
2106 if (!persona) {
2107 return EINVAL;
2108 }
2109
2110 if (!(persona->pspi_flags & (POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE | POSIX_SPAWN_PERSONA_FLAGS_VERIFY))) {
2111 return EINVAL;
2112 }
2113
2114 persona->pspi_ngroups = ngroups;
2115 for (int i = 0; i < ngroups; i++) {
2116 persona->pspi_groups[i] = gidarray[i];
2117 }
2118
2119 persona->pspi_gmuid = gmuid;
2120
2121 persona->pspi_flags |= POSIX_SPAWN_PERSONA_GROUPS;
2122
2123 return 0;
2124 }
2125
2126 int
2127 posix_spawnattr_set_max_addr_np(const posix_spawnattr_t * __restrict attr, uint64_t max_addr)
2128 {
2129 _posix_spawnattr_t psattr;
2130
2131 if (attr == NULL || *attr == NULL) {
2132 return EINVAL;
2133 }
2134
2135 psattr = *(_posix_spawnattr_t *)attr;
2136 psattr->psa_max_addr = max_addr;
2137
2138 return 0;
2139 }
2140
2141 static struct _posix_spawn_posix_cred_info *
2142 _posix_spawnattr_get_posix_creds_info(_posix_spawnattr_t psattr)
2143 {
2144 struct _posix_spawn_posix_cred_info *pspci = psattr->psa_posix_cred_info;
2145
2146 if (pspci == NULL) {
2147 pspci = malloc(sizeof(struct _posix_spawn_posix_cred_info));
2148 if (pspci != NULL) {
2149 pspci->pspci_flags = 0;
2150 pspci->pspci_uid = 0;
2151 pspci->pspci_gid = 0;
2152 pspci->pspci_ngroups = 0;
2153 pspci->pspci_groups[0] = 0;
2154 pspci->pspci_gmuid = 0;
2155 pspci->pspci_login[0] = '\0';
2156 psattr->psa_posix_cred_info = pspci;
2157 }
2158 }
2159 return pspci;
2160 }
2161
2162 int
2163 posix_spawnattr_set_uid_np(const posix_spawnattr_t *attr, uid_t uid)
2164 {
2165 struct _posix_spawn_posix_cred_info *pspci;
2166
2167 if (attr == NULL || *attr == NULL) {
2168 return EINVAL;
2169 }
2170
2171 pspci = _posix_spawnattr_get_posix_creds_info(*(_posix_spawnattr_t *)attr);
2172 if (pspci == NULL) {
2173 return ENOMEM;
2174 }
2175
2176 pspci->pspci_uid = uid;
2177
2178 pspci->pspci_flags |= POSIX_SPAWN_POSIX_CRED_UID;
2179
2180 return 0;
2181 }
2182
2183 int
2184 posix_spawnattr_set_gid_np(const posix_spawnattr_t *attr, gid_t gid)
2185 {
2186 struct _posix_spawn_posix_cred_info *pspci;
2187
2188 if (attr == NULL || *attr == NULL) {
2189 return EINVAL;
2190 }
2191
2192 pspci = _posix_spawnattr_get_posix_creds_info(*(_posix_spawnattr_t *)attr);
2193 if (pspci == NULL) {
2194 return ENOMEM;
2195 }
2196
2197 pspci->pspci_gid = gid;
2198
2199 pspci->pspci_flags |= POSIX_SPAWN_POSIX_CRED_GID;
2200
2201 return 0;
2202 }
2203
2204 int
2205 posix_spawnattr_set_groups_np(const posix_spawnattr_t *attr,
2206 int ngroups, gid_t *gidarray, uid_t gmuid)
2207 {
2208 struct _posix_spawn_posix_cred_info *pspci;
2209
2210 if (attr == NULL || *attr == NULL) {
2211 return EINVAL;
2212 }
2213
2214 if (gidarray == NULL) {
2215 return EINVAL;
2216 }
2217
2218 if (ngroups > NGROUPS || ngroups < 0) {
2219 return EINVAL;
2220 }
2221
2222 pspci = _posix_spawnattr_get_posix_creds_info(*(_posix_spawnattr_t *)attr);
2223 if (pspci == NULL) {
2224 return ENOMEM;
2225 }
2226
2227 pspci->pspci_ngroups = ngroups;
2228 for (int i = 0; i < ngroups; i++) {
2229 pspci->pspci_groups[i] = gidarray[i];
2230 }
2231
2232 pspci->pspci_gmuid = gmuid;
2233
2234 pspci->pspci_flags |= POSIX_SPAWN_POSIX_CRED_GROUPS;
2235
2236 return 0;
2237 }
2238
2239 int
2240 posix_spawnattr_set_login_np(const posix_spawnattr_t *attr, const char *login)
2241 {
2242 struct _posix_spawn_posix_cred_info *pspci;
2243
2244 if (attr == NULL || *attr == NULL) {
2245 return EINVAL;
2246 }
2247
2248 if (strlen(login) > MAXLOGNAME) {
2249 return ERANGE;
2250 }
2251
2252 pspci = _posix_spawnattr_get_posix_creds_info(*(_posix_spawnattr_t *)attr);
2253 if (pspci == NULL) {
2254 return ENOMEM;
2255 }
2256
2257 strlcpy(pspci->pspci_login, login, sizeof(pspci->pspci_login));
2258
2259 pspci->pspci_flags |= POSIX_SPAWN_POSIX_CRED_LOGIN;
2260
2261 return 0;
2262 }
2263
2264 /*
2265 * posix_spawnattr_set_jetsam_ttr_np
2266 *
2267 * Description: Pass data regarding recent relaunch behavior when jetsammed for the process.
2268 * The recent history is effectively converted into a histogram and the highest
2269 * frequency bucket defines the "type" of the process. The type is passed along
2270 * to the jetsam code as part of psa_jetsam_flags.
2271 *
2272 * Parameters: count Number of entries in the ttrs_millis array
2273 * ttrs_millis Array of raw data for relaunch behavior
2274 *
2275 * Returns: 0 Success
2276 * EINVAL Bad attr pointer or empty data array
2277 */
2278 int
2279 posix_spawnattr_set_jetsam_ttr_np(const posix_spawnattr_t * __restrict attr, uint32_t count, uint32_t *ttrs_millis)
2280 {
2281 _posix_spawnattr_t psattr;
2282
2283 /*
2284 * Define the bucketizing policy which would be used to generate the histogram. These
2285 * values are based on looking at data from various Avg. Joanna runs.
2286 */
2287 static const uint32_t relaunch_buckets_msecs[POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_BUCKETS] = {
2288 5000,
2289 10000,
2290 UINT32_MAX
2291 };
2292 static const uint32_t relaunch_jetsam_flags[POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_BUCKETS] = {
2293 POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_HIGH,
2294 POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_MED,
2295 POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_LOW
2296 };
2297
2298 /* Make sure the attr pointer is valid */
2299 if (attr == NULL || *attr == NULL) {
2300 return EINVAL;
2301 }
2302
2303 /* Make sure the count of entries is non-zero */
2304 if (count == 0) {
2305 return EINVAL;
2306 }
2307
2308 psattr = *(_posix_spawnattr_t *)attr;
2309
2310 /* Generate a histogram based on the relaunch data while maintaining highest frequency bucket info */
2311 int relaunch_histogram[POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_BUCKETS] = {0};
2312 int max_frequency = -1;
2313 int highest_frequency_bucket = -1;
2314
2315 for (uint32_t i = 0; i < count; i++) {
2316 /* For each data point passed in via launchd, find the bucket it lands in */
2317 for (uint32_t bucket = 0; bucket < POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_BUCKETS; bucket++) {
2318 if (ttrs_millis[i] <= relaunch_buckets_msecs[bucket]) {
2319 relaunch_histogram[bucket]++;
2320
2321 /* Check if the bucket is the highest frequency bucket now */
2322 if (relaunch_histogram[bucket] > max_frequency) {
2323 max_frequency = relaunch_histogram[bucket];
2324 highest_frequency_bucket = bucket;
2325 }
2326 break;
2327 }
2328 }
2329 }
2330 psattr->psa_jetsam_flags |= relaunch_jetsam_flags[highest_frequency_bucket];
2331 return 0;
2332 }
2333
2334 /*
2335 * posix_spawn
2336 *
2337 * Description: Create a new process from the process image corresponding to
2338 * the supplied 'path' argument.
2339 *
2340 * Parameters: pid Pointer to pid_t to receive the
2341 * PID of the spawned process, if
2342 * successful and 'pid' != NULL
2343 * path Path of image file to spawn
2344 * file_actions spawn file actions object which
2345 * describes file actions to be
2346 * performed during the spawn
2347 * attrp spawn attributes object which
2348 * describes attributes to be
2349 * applied during the spawn
2350 * argv argument vector array; NULL
2351 * terminated
2352 * envp environment vector array; NULL
2353 * terminated
2354 *
2355 * Returns: 0 Success
2356 * !0 An errno value indicating the
2357 * cause of the failure to spawn
2358 *
2359 * Notes: Unlike other system calls, the return value of this system
2360 * call is expected to either be a 0 or an errno, rather than a
2361 * 0 or a -1, with the 'errno' variable being set.
2362 */
2363 extern int __posix_spawn(pid_t * __restrict, const char * __restrict,
2364 struct _posix_spawn_args_desc *,
2365 char *const argv[__restrict], char *const envp[__restrict]);
2366
2367 int
2368 posix_spawn(pid_t * __restrict pid, const char * __restrict path,
2369 const posix_spawn_file_actions_t *file_actions,
2370 const posix_spawnattr_t * __restrict attrp,
2371 char *const argv[__restrict], char *const envp[__restrict])
2372 {
2373 int saveerrno = errno;
2374 int ret;
2375 /*
2376 * Only do extra work if we have file actions or attributes to push
2377 * down. We use a descriptor to push this information down, since we
2378 * want to have size information, which will let us (1) preallocate a
2379 * single chunk of memory for the copyin(), and (2) allow us to do a
2380 * single copyin() per attributes or file actions as a monlithic block.
2381 *
2382 * Note: A future implementation may attempt to do the same
2383 * thing for the argv/envp data, which could potentially
2384 * result in a performance improvement due to increased
2385 * kernel efficiency, even though it would mean copying
2386 * the data in user space.
2387 */
2388 if ((file_actions != NULL && (*file_actions != NULL) && (*(_posix_spawn_file_actions_t *)file_actions)->psfa_act_count > 0) || attrp != NULL) {
2389 struct _posix_spawn_args_desc ad;
2390
2391 memset(&ad, 0, sizeof(ad));
2392 if (attrp != NULL && *attrp != NULL) {
2393 _posix_spawnattr_t psattr = *(_posix_spawnattr_t *)attrp;
2394 ad.attr_size = sizeof(struct _posix_spawnattr);
2395 ad.attrp = psattr;
2396
2397 if (psattr->psa_ports != NULL) {
2398 size_t psact_size = PS_PORT_ACTIONS_SIZE(psattr->psa_ports->pspa_count);
2399 if (psact_size == 0 && psattr->psa_ports->pspa_count != 0) {
2400 errno = EINVAL;
2401 ret = -1;
2402 goto out;
2403 }
2404 ad.port_actions = psattr->psa_ports;
2405 ad.port_actions_size = psact_size;
2406 }
2407 if (psattr->psa_mac_extensions != NULL) {
2408 size_t macext_size = PS_MAC_EXTENSIONS_SIZE(psattr->psa_mac_extensions->psmx_count);
2409 if (macext_size == 0 && psattr->psa_mac_extensions->psmx_count != 0) {
2410 errno = EINVAL;
2411 ret = -1;
2412 goto out;
2413 }
2414 ad.mac_extensions = psattr->psa_mac_extensions;
2415 ad.mac_extensions_size = macext_size;
2416 }
2417 if (psattr->psa_coalition_info != NULL) {
2418 ad.coal_info_size = sizeof(struct _posix_spawn_coalition_info);
2419 ad.coal_info = psattr->psa_coalition_info;
2420 }
2421 if (psattr->psa_persona_info != NULL) {
2422 ad.persona_info_size = sizeof(struct _posix_spawn_persona_info);
2423 ad.persona_info = psattr->psa_persona_info;
2424 }
2425 if (psattr->psa_posix_cred_info != NULL) {
2426 ad.posix_cred_info_size = sizeof(struct _posix_spawn_posix_cred_info);
2427 ad.posix_cred_info = psattr->psa_posix_cred_info;
2428 }
2429 }
2430 if (file_actions != NULL && *file_actions != NULL) {
2431 _posix_spawn_file_actions_t psactsp =
2432 *(_posix_spawn_file_actions_t *)file_actions;
2433
2434 if (psactsp->psfa_act_count > 0) {
2435 size_t fa_size = PSF_ACTIONS_SIZE(psactsp->psfa_act_count);
2436 if (fa_size == 0 && psactsp->psfa_act_count != 0) {
2437 errno = EINVAL;
2438 ret = -1;
2439 goto out;
2440 }
2441 ad.file_actions_size = fa_size;
2442 ad.file_actions = psactsp;
2443 }
2444 }
2445
2446 ret = __posix_spawn(pid, path, &ad, argv, envp);
2447 } else {
2448 ret = __posix_spawn(pid, path, NULL, argv, envp);
2449 }
2450
2451 out:
2452 if (ret < 0) {
2453 ret = errno;
2454 }
2455 errno = saveerrno;
2456 return ret;
2457 }