]> git.saurik.com Git - apple/xnu.git/blob - libsyscall/wrappers/spawn/posix_spawn.c
xnu-6153.61.1.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_setexceptionports_np
948 *
949 * Description: Set a new port for a set of exception ports in the spawned task.
950 *
951 * Parameters: attr The spawn attributes object for the
952 * new process
953 * mask A bitfield indicating which exceptions
954 * to associate the port with
955 * new_port The new value for the exception port
956 * behavior The default behavior for the port
957 * flavor The default flavor for the port
958 * (see task_set_exception_ports)
959 *
960 * Returns: 0 Success
961 */
962 int
963 posix_spawnattr_setexceptionports_np(
964 posix_spawnattr_t *attr,
965 exception_mask_t mask,
966 mach_port_t new_port,
967 exception_behavior_t behavior,
968 thread_state_flavor_t flavor)
969 {
970 _ps_port_action_t action = {
971 .port_type = PSPA_EXCEPTION,
972 .mask = mask,
973 .new_port = new_port,
974 .behavior = behavior,
975 .flavor = flavor,
976 };
977 return posix_spawn_appendportaction_np(attr, &action);
978 }
979
980 /*
981 * posix_spawnattr_setauditsessionport_np
982 *
983 * Description: Set the audit session port rights attribute in the spawned task.
984 * This is used to securely set the audit session information for
985 * the new task.
986 *
987 * Parameters: attr The spawn attributes object for the
988 * new process
989 * au_sessionport The audit session send port right
990 *
991 * Returns: 0 Success
992 */
993 int
994 posix_spawnattr_setauditsessionport_np(
995 posix_spawnattr_t *attr,
996 mach_port_t au_sessionport)
997 {
998 _ps_port_action_t action = {
999 .port_type = PSPA_AU_SESSION,
1000 .new_port = au_sessionport,
1001 };
1002 return posix_spawn_appendportaction_np(attr, &action);
1003 }
1004
1005
1006 /*
1007 * posix_spawn_file_actions_init
1008 *
1009 * Description: Initialize a spawn file actions object attr with default values
1010 *
1011 * Parameters: file_actions The spawn file actions object to be
1012 * initialized
1013 *
1014 * Returns: 0 Success
1015 * ENOMEM Insufficient memory exists to
1016 * initialize the spawn file actions
1017 * object.
1018 *
1019 * Note: As an implementation detail, the externally visibily type
1020 * posix_spawn_file_actions_t is defined to be a void *, and
1021 * initialization involves allocation of a memory object.
1022 * Subsequent changes to the spawn file actions may result in
1023 * reallocation under the covers.
1024 *
1025 * Reinitialization of an already initialized spawn file actions
1026 * object will result in memory being leaked. Because spawn
1027 * file actions are not required to be used in conjunction with a
1028 * static initializer, there is no way to distinguish a spawn
1029 * file actions with stack garbage from one that's been
1030 * initialized. This is arguably an API design error.
1031 */
1032 int
1033 posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions)
1034 {
1035 _posix_spawn_file_actions_t *psactsp = (_posix_spawn_file_actions_t *)file_actions;
1036 int err = 0;
1037
1038 if ((*psactsp = (_posix_spawn_file_actions_t)malloc(PSF_ACTIONS_SIZE(PSF_ACTIONS_INIT_COUNT))) == NULL) {
1039 err = ENOMEM;
1040 } else {
1041 (*psactsp)->psfa_act_alloc = PSF_ACTIONS_INIT_COUNT;
1042 (*psactsp)->psfa_act_count = 0;
1043 }
1044
1045 return err;
1046 }
1047
1048
1049 /*
1050 * posix_spawn_file_actions_destroy
1051 *
1052 * Description: Destroy a spawn file actions object that was previously
1053 * initialized via posix_spawn_file_actions_init() by freeing any
1054 * memory associated with it and setting it to an invalid value.
1055 *
1056 * Parameters: attr The spawn file actions object to be
1057 * destroyed.
1058 *
1059 * Returns: 0 Success
1060 *
1061 * Notes: The destroyed spawn file actions results in the void * pointer
1062 * being set to NULL; subsequent use without reinitialization
1063 * will result in explicit program failure (rather than merely
1064 * "undefined behaviour").
1065 *
1066 * NOTIMP: Allowed failures (checking NOT required):
1067 * EINVAL The value specified by file_actions is invalid.
1068 */
1069 int
1070 posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions)
1071 {
1072 _posix_spawn_file_actions_t psacts;
1073
1074 if (file_actions == NULL || *file_actions == NULL) {
1075 return EINVAL;
1076 }
1077
1078 psacts = *(_posix_spawn_file_actions_t *)file_actions;
1079 free(psacts);
1080 *file_actions = NULL;
1081
1082 return 0;
1083 }
1084
1085
1086 /*
1087 * _posix_spawn_file_actions_grow
1088 *
1089 * Description: Grow the available list of file actions associated with the
1090 * pointer to the structure provided; replace the contents of the
1091 * pointer as a side effect.
1092 *
1093 * Parameters: psactsp Pointer to _posix_spawn_file_actions_t
1094 * to grow
1095 *
1096 * Returns: 0 Success
1097 * ENOMEM Insufficient memory for operation
1098 *
1099 * Notes: This code is common to all posix_spawn_file_actions_*()
1100 * functions, since we use a naieve data structure implementation
1101 * at present. Future optimization will likely change this.
1102 */
1103 static int
1104 _posix_spawn_file_actions_grow(_posix_spawn_file_actions_t *psactsp)
1105 {
1106 int newnum = 0;
1107 if (os_mul_overflow((*psactsp)->psfa_act_alloc, 2, &newnum)) {
1108 return ENOMEM;
1109 }
1110
1111 size_t newsize = PSF_ACTIONS_SIZE(newnum);
1112 if (newsize == 0) {
1113 return ENOMEM;
1114 }
1115
1116 /*
1117 * XXX may want to impose an administrative limit here; POSIX does
1118 * XXX not provide for an administrative error return in this case,
1119 * XXX so it's probably acceptable to just fail catastrophically
1120 * XXX instead of implementing one.
1121 */
1122 _posix_spawn_file_actions_t new_psacts;
1123 if ((new_psacts = (_posix_spawn_file_actions_t)realloc((*psactsp), newsize)) == NULL) {
1124 return ENOMEM;
1125 }
1126 new_psacts->psfa_act_alloc = newnum;
1127 *psactsp = new_psacts;
1128
1129 return 0;
1130 }
1131
1132
1133 /*
1134 * posix_spawn_file_actions_addopen
1135 *
1136 * Description: Add an open action to the object referenced by 'file_actions'
1137 * that will cause the file named by 'path' to be attempted to be
1138 * opened with flags 'oflag' and mode 'mode', and, if successful,
1139 * return as descriptor 'filedes' to the spawned process.
1140 *
1141 * Parameters: file_actions File action object to augment
1142 * filedes fd that open is to use
1143 * path path to file to open
1144 * oflag open file flags
1145 * mode open file mode
1146 *
1147 * Returns: 0 Success
1148 * EBADF The value specified by fildes is
1149 * negative or greater than or equal to
1150 * {OPEN_MAX}.
1151 * ENOMEM Insufficient memory exists to add to
1152 * the spawn file actions object.
1153 *
1154 * NOTIMP: Allowed failures (checking NOT required):
1155 * EINVAL The value specified by file_actions is invalid.
1156 */
1157 int
1158 posix_spawn_file_actions_addopen(
1159 posix_spawn_file_actions_t * __restrict file_actions,
1160 int filedes, const char * __restrict path, int oflag,
1161 mode_t mode)
1162 {
1163 _posix_spawn_file_actions_t *psactsp;
1164 _psfa_action_t *psfileact;
1165
1166 if (file_actions == NULL || *file_actions == NULL) {
1167 return EINVAL;
1168 }
1169
1170 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1171 /* Range check; required by POSIX */
1172 if (filedes < 0 || filedes >= OPEN_MAX) {
1173 return EBADF;
1174 }
1175
1176 /* If we do not have enough slots, grow the structure */
1177 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1178 /* need to grow file actions structure */
1179 if (_posix_spawn_file_actions_grow(psactsp)) {
1180 return ENOMEM;
1181 }
1182 }
1183
1184 /*
1185 * Allocate next available slot and fill it out
1186 */
1187 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1188
1189 psfileact->psfaa_type = PSFA_OPEN;
1190 psfileact->psfaa_filedes = filedes;
1191 psfileact->psfaa_openargs.psfao_oflag = oflag;
1192 psfileact->psfaa_openargs.psfao_mode = mode;
1193 strlcpy(psfileact->psfaa_openargs.psfao_path, path, PATH_MAX);
1194
1195 return 0;
1196 }
1197
1198
1199 /*
1200 * posix_spawn_file_actions_addclose
1201 *
1202 * Description: Add a close action to the object referenced by 'file_actions'
1203 * that will cause the file referenced by 'filedes' to be
1204 * attempted to be closed in the spawned process.
1205 *
1206 * Parameters: file_actions File action object to augment
1207 * filedes fd to close
1208 *
1209 * Returns: 0 Success
1210 * EBADF The value specified by fildes is
1211 * negative or greater than or equal to
1212 * {OPEN_MAX}.
1213 * ENOMEM Insufficient memory exists to add to
1214 * the spawn file actions object.
1215 *
1216 * NOTIMP: Allowed failures (checking NOT required):
1217 * EINVAL The value specified by file_actions is invalid.
1218 */
1219 int
1220 posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions,
1221 int filedes)
1222 {
1223 _posix_spawn_file_actions_t *psactsp;
1224 _psfa_action_t *psfileact;
1225
1226 if (file_actions == NULL || *file_actions == NULL) {
1227 return EINVAL;
1228 }
1229
1230 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1231 /* Range check; required by POSIX */
1232 if (filedes < 0 || filedes >= OPEN_MAX) {
1233 return EBADF;
1234 }
1235
1236 /* If we do not have enough slots, grow the structure */
1237 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1238 /* need to grow file actions structure */
1239 if (_posix_spawn_file_actions_grow(psactsp)) {
1240 return ENOMEM;
1241 }
1242 }
1243
1244 /*
1245 * Allocate next available slot and fill it out
1246 */
1247 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1248
1249 psfileact->psfaa_type = PSFA_CLOSE;
1250 psfileact->psfaa_filedes = filedes;
1251
1252 return 0;
1253 }
1254
1255
1256 /*
1257 * posix_spawn_file_actions_adddup2
1258 *
1259 * Description: Add a dup2 action to the object referenced by 'file_actions'
1260 * that will cause the file referenced by 'filedes' to be
1261 * attempted to be dup2'ed to the descriptor 'newfiledes' in the
1262 * spawned process.
1263 *
1264 * Parameters: file_actions File action object to augment
1265 * filedes fd to dup2
1266 * newfiledes fd to dup2 it to
1267 *
1268 * Returns: 0 Success
1269 * EBADF The value specified by either fildes
1270 * or by newfiledes is negative or greater
1271 * than or equal to {OPEN_MAX}.
1272 * ENOMEM Insufficient memory exists to add to
1273 * the spawn file actions object.
1274 *
1275 * NOTIMP: Allowed failures (checking NOT required):
1276 * EINVAL The value specified by file_actions is invalid.
1277 */
1278 int
1279 posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions,
1280 int filedes, int newfiledes)
1281 {
1282 _posix_spawn_file_actions_t *psactsp;
1283 _psfa_action_t *psfileact;
1284
1285 if (file_actions == NULL || *file_actions == NULL) {
1286 return EINVAL;
1287 }
1288
1289 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1290 /* Range check; required by POSIX */
1291 if (filedes < 0 || filedes >= OPEN_MAX ||
1292 newfiledes < 0 || newfiledes >= OPEN_MAX) {
1293 return EBADF;
1294 }
1295
1296 /* If we do not have enough slots, grow the structure */
1297 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1298 /* need to grow file actions structure */
1299 if (_posix_spawn_file_actions_grow(psactsp)) {
1300 return ENOMEM;
1301 }
1302 }
1303
1304 /*
1305 * Allocate next available slot and fill it out
1306 */
1307 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1308
1309 psfileact->psfaa_type = PSFA_DUP2;
1310 psfileact->psfaa_filedes = filedes;
1311 psfileact->psfaa_dup2args.psfad_newfiledes = newfiledes;
1312
1313 return 0;
1314 }
1315
1316 /*
1317 * posix_spawn_file_actions_add_fileportdup2_np
1318 *
1319 * Description: Add a dup2 action to the object referenced by 'file_actions'
1320 * that will cause the file referenced by 'fileport' to be
1321 * attempted to be dup2'ed to the descriptor 'newfiledes' in the
1322 * spawned process.
1323 *
1324 * Parameters: file_actions File action object to augment
1325 * filedes fileport to dup2
1326 * newfiledes fd to dup2 it to
1327 *
1328 * Returns: 0 Success
1329 * EBADF fileport isn't a valid port, or the
1330 * value specified by newfiledes is
1331 * negative or greater than or equal to
1332 * {OPEN_MAX}.
1333 * ENOMEM Insufficient memory exists to add to
1334 * the spawn file actions object.
1335 *
1336 * NOTIMP: Allowed failures (checking NOT required):
1337 * EINVAL The value specified by file_actions is invalid.
1338 */
1339 int
1340 posix_spawn_file_actions_add_fileportdup2_np(
1341 posix_spawn_file_actions_t *file_actions,
1342 mach_port_t fileport, int newfiledes)
1343 {
1344 _posix_spawn_file_actions_t *psactsp;
1345 _psfa_action_t *psfileact;
1346
1347 if (file_actions == NULL || *file_actions == NULL) {
1348 return EINVAL;
1349 }
1350
1351 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1352 /* Range check; required by POSIX */
1353 if (!MACH_PORT_VALID(fileport) ||
1354 newfiledes < 0 || newfiledes >= OPEN_MAX) {
1355 return EBADF;
1356 }
1357
1358 /* If we do not have enough slots, grow the structure */
1359 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1360 /* need to grow file actions structure */
1361 if (_posix_spawn_file_actions_grow(psactsp)) {
1362 return ENOMEM;
1363 }
1364 }
1365
1366 /*
1367 * Allocate next available slot and fill it out
1368 */
1369 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1370
1371 psfileact->psfaa_type = PSFA_FILEPORT_DUP2;
1372 psfileact->psfaa_fileport = fileport;
1373 psfileact->psfaa_dup2args.psfad_newfiledes = newfiledes;
1374
1375 return 0;
1376 }
1377
1378 /*
1379 * posix_spawn_file_actions_addinherit_np
1380 *
1381 * Description: Add the "inherit" action to the object referenced by
1382 * 'file_actions' that will cause the file referenced by
1383 * 'filedes' to continue to be available in the spawned
1384 * process via the same descriptor.
1385 *
1386 * Inheritance is the normal default behaviour for
1387 * file descriptors across exec and spawn; but if the
1388 * POSIX_SPAWN_CLOEXEC_DEFAULT flag is set, the usual
1389 * default is reversed for the purposes of the spawn
1390 * invocation. Any pre-existing descriptors that
1391 * need to be made available to the spawned process can
1392 * be marked explicitly as 'inherit' via this interface.
1393 * Otherwise they will be automatically closed.
1394 *
1395 * Note that any descriptors created via the other file
1396 * actions interfaces are automatically marked as 'inherit'.
1397 *
1398 * Parameters: file_actions File action object to augment
1399 * filedes fd to inherit.
1400 *
1401 * Returns: 0 Success
1402 * EBADF The value specified by fildes is
1403 * negative or greater than or equal to
1404 * {OPEN_MAX}.
1405 * ENOMEM Insufficient memory exists to add to
1406 * the spawn file actions object.
1407 *
1408 * NOTIMP: Allowed failures (checking NOT required):
1409 * EINVAL The value specified by file_actions is invalid.
1410 */
1411 int
1412 posix_spawn_file_actions_addinherit_np(posix_spawn_file_actions_t *file_actions,
1413 int filedes)
1414 {
1415 _posix_spawn_file_actions_t *psactsp;
1416 _psfa_action_t *psfileact;
1417
1418 if (file_actions == NULL || *file_actions == NULL) {
1419 return EINVAL;
1420 }
1421
1422 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1423 /* Range check; required by POSIX */
1424 if (filedes < 0 || filedes >= OPEN_MAX) {
1425 return EBADF;
1426 }
1427
1428 #if defined(POSIX_SPAWN_CLOEXEC_DEFAULT) // TODO: delete this check
1429 /* If we do not have enough slots, grow the structure */
1430 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1431 /* need to grow file actions structure */
1432 if (_posix_spawn_file_actions_grow(psactsp)) {
1433 return ENOMEM;
1434 }
1435 }
1436
1437 /*
1438 * Allocate next available slot and fill it out
1439 */
1440 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1441
1442 psfileact->psfaa_type = PSFA_INHERIT;
1443 psfileact->psfaa_filedes = filedes;
1444 #endif
1445 return 0;
1446 }
1447
1448
1449 /*
1450 * posix_spawn_file_actions_addchdir_np
1451 *
1452 * Description: Add a chdir action to the object referenced by 'file_actions'
1453 * that will cause the current working directory to attempt to be changed
1454 * to that referenced by 'path' in the spawned process.
1455 *
1456 * Parameters: file_actions File action object to augment
1457 * path path of the desired working directory
1458 *
1459 * Returns: 0 Success
1460 * ENOMEM Insufficient memory exists to add to
1461 * the spawn file actions object.
1462 * ENAMETOOLONG The supplied path exceeded PATH_MAX.
1463 *
1464 * NOTIMP: Allowed failures (checking NOT required):
1465 * EINVAL The value specified by file_actions is invalid.
1466 */
1467 int
1468 posix_spawn_file_actions_addchdir_np(
1469 posix_spawn_file_actions_t * __restrict file_actions,
1470 const char * __restrict path)
1471 {
1472 _posix_spawn_file_actions_t *psactsp;
1473 _psfa_action_t *psfileact;
1474
1475 if (file_actions == NULL || *file_actions == NULL) {
1476 return EINVAL;
1477 }
1478
1479 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1480
1481 /* If we do not have enough slots, grow the structure */
1482 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1483 /* need to grow file actions structure */
1484 if (_posix_spawn_file_actions_grow(psactsp)) {
1485 return ENOMEM;
1486 }
1487 }
1488
1489 /*
1490 * Allocate next available slot and fill it out
1491 */
1492 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1493
1494 psfileact->psfaa_type = PSFA_CHDIR;
1495 if (strlcpy(psfileact->psfaa_chdirargs.psfac_path, path, PATH_MAX) >= PATH_MAX) {
1496 (*psactsp)->psfa_act_count--;
1497 return ENAMETOOLONG;
1498 }
1499
1500 return 0;
1501 }
1502
1503
1504 /*
1505 * posix_spawn_file_actions_fchdir_np
1506 *
1507 * Description: Add a fchdir action to the object referenced by 'file_actions'
1508 * that will cause the current working directory to attempt to be changed
1509 * to that referenced by the descriptor 'filedes' in the spawned process.
1510 *
1511 * Parameters: file_actions File action object to augment
1512 * filedes fd to chdir to
1513 *
1514 * Returns: 0 Success
1515 * EBADF The value specified by either fildes is negative or
1516 * greater than or equal to {OPEN_MAX}.
1517 * ENOMEM Insufficient memory exists to add to
1518 * the spawn file actions object.
1519 *
1520 * NOTIMP: Allowed failures (checking NOT required):
1521 * EINVAL The value specified by file_actions is invalid.
1522 */
1523 int
1524 posix_spawn_file_actions_addfchdir_np(posix_spawn_file_actions_t *file_actions,
1525 int filedes)
1526 {
1527 _posix_spawn_file_actions_t *psactsp;
1528 _psfa_action_t *psfileact;
1529
1530 if (file_actions == NULL || *file_actions == NULL) {
1531 return EINVAL;
1532 }
1533
1534 psactsp = (_posix_spawn_file_actions_t *)file_actions;
1535 /* Range check; in spirit of POSIX */
1536 if (filedes < 0 || filedes >= OPEN_MAX) {
1537 return EBADF;
1538 }
1539
1540 /* If we do not have enough slots, grow the structure */
1541 if ((*psactsp)->psfa_act_count == (*psactsp)->psfa_act_alloc) {
1542 /* need to grow file actions structure */
1543 if (_posix_spawn_file_actions_grow(psactsp)) {
1544 return ENOMEM;
1545 }
1546 }
1547
1548 /*
1549 * Allocate next available slot and fill it out
1550 */
1551 psfileact = &(*psactsp)->psfa_act_acts[(*psactsp)->psfa_act_count++];
1552
1553 psfileact->psfaa_type = PSFA_FCHDIR;
1554 psfileact->psfaa_filedes = filedes;
1555
1556 return 0;
1557 }
1558
1559 int
1560 posix_spawnattr_setcpumonitor_default(posix_spawnattr_t * __restrict attr)
1561 {
1562 return posix_spawnattr_setcpumonitor(attr, PROC_POLICY_CPUMON_DEFAULTS, 0);
1563 }
1564
1565 int
1566 posix_spawnattr_setcpumonitor(posix_spawnattr_t * __restrict attr,
1567 uint64_t percent, uint64_t interval)
1568 {
1569 _posix_spawnattr_t psattr;
1570
1571 if (attr == NULL || *attr == NULL) {
1572 return EINVAL;
1573 }
1574
1575 psattr = *(_posix_spawnattr_t *)attr;
1576
1577 psattr->psa_cpumonitor_percent = percent;
1578 psattr->psa_cpumonitor_interval = interval;
1579
1580 return 0;
1581 }
1582
1583 int
1584 posix_spawnattr_getcpumonitor(posix_spawnattr_t * __restrict attr,
1585 uint64_t *percent, uint64_t *interval)
1586 {
1587 _posix_spawnattr_t psattr;
1588
1589 if (attr == NULL || *attr == NULL) {
1590 return EINVAL;
1591 }
1592
1593 psattr = *(_posix_spawnattr_t *)attr;
1594
1595 *percent = psattr->psa_cpumonitor_percent;
1596 *interval = psattr->psa_cpumonitor_interval;
1597
1598 return 0;
1599 }
1600
1601 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
1602 /*
1603 * posix_spawnattr_setjetsam
1604 *
1605 * Description: Set jetsam attributes for the spawn attribute object
1606 * referred to by 'attr'.
1607 *
1608 * Parameters: flags The flags value to set
1609 * priority Relative jetsam priority
1610 * memlimit Value in megabytes; a memory footprint
1611 * above this level may result in termination.
1612 * Implies both active and inactive limits.
1613 *
1614 * Returns: 0 Success
1615 *
1616 * Note: to be deprecated (not available on desktop)
1617 *
1618 */
1619 int
1620 posix_spawnattr_setjetsam(posix_spawnattr_t * __restrict attr,
1621 short flags, int priority, int memlimit)
1622 {
1623 short flags_ext = flags;
1624
1625 if (flags & POSIX_SPAWN_JETSAM_MEMLIMIT_FATAL) {
1626 flags_ext |= POSIX_SPAWN_JETSAM_MEMLIMIT_ACTIVE_FATAL;
1627 flags_ext |= POSIX_SPAWN_JETSAM_MEMLIMIT_INACTIVE_FATAL;
1628 } else {
1629 flags_ext &= ~POSIX_SPAWN_JETSAM_MEMLIMIT_ACTIVE_FATAL;
1630 flags_ext &= ~POSIX_SPAWN_JETSAM_MEMLIMIT_INACTIVE_FATAL;
1631 }
1632
1633 return posix_spawnattr_setjetsam_ext(attr, flags_ext, priority, memlimit, memlimit);
1634 }
1635 #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
1636
1637 /*
1638 * posix_spawnattr_setjetsam_ext
1639 *
1640 * Description: Set jetsam attributes for the spawn attribute object
1641 * referred to by 'attr'.
1642 *
1643 * Parameters: flags The flags value to set
1644 * priority Relative jetsam priority
1645 * memlimit_active Value in megabytes; memory footprint
1646 * above this level while process is
1647 * active may result in termination.
1648 * memlimit_inactive Value in megabytes; memory footprint
1649 * above this level while process is
1650 * inactive may result in termination.
1651 *
1652 * Returns: 0 Success
1653 */
1654 int
1655 posix_spawnattr_setjetsam_ext(posix_spawnattr_t * __restrict attr,
1656 short flags, int priority, int memlimit_active, int memlimit_inactive)
1657 {
1658 _posix_spawnattr_t psattr;
1659
1660 if (attr == NULL || *attr == NULL) {
1661 return EINVAL;
1662 }
1663
1664 psattr = *(_posix_spawnattr_t *)attr;
1665
1666 psattr->psa_jetsam_flags = flags;
1667 psattr->psa_jetsam_flags |= POSIX_SPAWN_JETSAM_SET;
1668 psattr->psa_priority = priority;
1669 psattr->psa_memlimit_active = memlimit_active;
1670 psattr->psa_memlimit_inactive = memlimit_inactive;
1671
1672 return 0;
1673 }
1674
1675 int
1676 posix_spawnattr_set_threadlimit_ext(posix_spawnattr_t * __restrict attr,
1677 int thread_limit)
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_thread_limit = thread_limit;
1688
1689 return 0;
1690 }
1691
1692
1693 /*
1694 * posix_spawnattr_set_importancewatch_port_np
1695 *
1696 * Description: Mark ports referred to by these rights
1697 * to boost the new task instead of their current task
1698 * for the spawn attribute object referred to by 'attr'.
1699 * Ports must be valid at posix_spawn time. They will NOT be
1700 * consumed by the kernel, so they must be deallocated after the spawn returns.
1701 * (If you are SETEXEC-ing, they are cleaned up by the exec operation).
1702 *
1703 * The maximum number of watch ports allowed is defined by POSIX_SPAWN_IMPORTANCE_PORT_COUNT.
1704 *
1705 * Parameters: count Number of ports in portarray
1706 * portarray Array of rights
1707 *
1708 * Returns: 0 Success
1709 * EINVAL Bad port count
1710 * ENOMEM Insufficient memory exists to add to
1711 * the spawn port actions object.
1712 */
1713 int
1714 posix_spawnattr_set_importancewatch_port_np(posix_spawnattr_t * __restrict attr,
1715 int count, mach_port_t portarray[])
1716 {
1717 int err = 0, i;
1718
1719 if (count < 0 || count > POSIX_SPAWN_IMPORTANCE_PORT_COUNT) {
1720 return EINVAL;
1721 }
1722
1723 for (i = 0; i < count; i++) {
1724 _ps_port_action_t action = {
1725 .port_type = PSPA_IMP_WATCHPORTS,
1726 .new_port = portarray[i],
1727 };
1728 err = posix_spawn_appendportaction_np(attr, &action);
1729 if (err) {
1730 break;
1731 }
1732 }
1733 return err;
1734 }
1735
1736 int
1737 posix_spawnattr_set_registered_ports_np(posix_spawnattr_t * __restrict attr,
1738 mach_port_t portarray[], uint32_t count)
1739 {
1740 int err = 0;
1741
1742 if (count > TASK_PORT_REGISTER_MAX) {
1743 return EINVAL;
1744 }
1745
1746 for (uint32_t i = 0; i < count; i++) {
1747 _ps_port_action_t action = {
1748 .port_type = PSPA_REGISTERED_PORTS,
1749 .new_port = portarray[i],
1750 };
1751 err = posix_spawn_appendportaction_np(attr, &action);
1752 if (err) {
1753 break;
1754 }
1755 }
1756 return err;
1757 }
1758
1759
1760 static
1761 _ps_mac_policy_extension_t *
1762 posix_spawnattr_macpolicyinfo_lookup(_posix_spawn_mac_policy_extensions_t psmx, const char *policyname)
1763 {
1764 int i;
1765
1766 if (psmx == NULL) {
1767 return NULL;
1768 }
1769
1770 for (i = 0; i < psmx->psmx_count; i++) {
1771 _ps_mac_policy_extension_t *extension = &psmx->psmx_extensions[i];
1772 if (strcmp(extension->policyname, policyname) == 0) {
1773 return extension;
1774 }
1775 }
1776 return NULL;
1777 }
1778
1779 int
1780 posix_spawnattr_getmacpolicyinfo_np(const posix_spawnattr_t * __restrict attr,
1781 const char *policyname, void **datap, size_t *datalenp)
1782 {
1783 _posix_spawnattr_t psattr;
1784 _ps_mac_policy_extension_t *extension;
1785
1786 if (attr == NULL || *attr == NULL || policyname == NULL || datap == NULL) {
1787 return EINVAL;
1788 }
1789
1790 psattr = *(_posix_spawnattr_t *)attr;
1791 extension = posix_spawnattr_macpolicyinfo_lookup(psattr->psa_mac_extensions, policyname);
1792 if (extension == NULL) {
1793 return ESRCH;
1794 }
1795 *datap = (void *)(uintptr_t)extension->data;
1796 if (datalenp != NULL) {
1797 *datalenp = (size_t)extension->datalen;
1798 }
1799 return 0;
1800 }
1801
1802 int
1803 posix_spawnattr_setmacpolicyinfo_np(posix_spawnattr_t * __restrict attr,
1804 const char *policyname, void *data, size_t datalen)
1805 {
1806 _posix_spawnattr_t psattr;
1807 _posix_spawn_mac_policy_extensions_t psmx;
1808 _ps_mac_policy_extension_t *extension;
1809
1810 if (attr == NULL || *attr == NULL || policyname == NULL) {
1811 return EINVAL;
1812 }
1813
1814 psattr = *(_posix_spawnattr_t *)attr;
1815 psmx = psattr->psa_mac_extensions;
1816 extension = posix_spawnattr_macpolicyinfo_lookup(psattr->psa_mac_extensions, policyname);
1817 if (extension != NULL) {
1818 extension->data = (uintptr_t)data;
1819 extension->datalen = datalen;
1820 return 0;
1821 } else if (psmx == NULL) {
1822 psmx = psattr->psa_mac_extensions = malloc(PS_MAC_EXTENSIONS_SIZE(PS_MAC_EXTENSIONS_INIT_COUNT));
1823 if (psmx == NULL) {
1824 return ENOMEM;
1825 }
1826 psmx->psmx_alloc = PS_MAC_EXTENSIONS_INIT_COUNT;
1827 psmx->psmx_count = 0;
1828 } else if (psmx->psmx_count == psmx->psmx_alloc) {
1829 int newnum = 0;
1830 if (os_mul_overflow(psmx->psmx_alloc, 2, &newnum)) {
1831 return ENOMEM;
1832 }
1833 size_t extsize = PS_MAC_EXTENSIONS_SIZE(newnum);
1834 if (extsize == 0) {
1835 return ENOMEM;
1836 }
1837 psmx = psattr->psa_mac_extensions = reallocf(psmx, extsize);
1838 if (psmx == NULL) {
1839 return ENOMEM;
1840 }
1841 psmx->psmx_alloc = newnum;
1842 }
1843 extension = &psmx->psmx_extensions[psmx->psmx_count];
1844 strlcpy(extension->policyname, policyname, sizeof(extension->policyname));
1845 extension->data = (uintptr_t)data;
1846 extension->datalen = datalen;
1847 psmx->psmx_count += 1;
1848 return 0;
1849 }
1850
1851 /*
1852 * posix_spawn_destroymacpolicy_info_np
1853 * Description: cleanup the macpolicy struct in posix_spawnattr_t attr
1854 */
1855 static int
1856 posix_spawn_destroymacpolicy_info_np(posix_spawnattr_t *attr)
1857 {
1858 _posix_spawnattr_t psattr;
1859 _posix_spawn_mac_policy_extensions_t psmx;
1860
1861 if (attr == NULL || *attr == NULL) {
1862 return EINVAL;
1863 }
1864
1865 psattr = *(_posix_spawnattr_t *)attr;
1866 psmx = psattr->psa_mac_extensions;
1867 if (psmx == NULL) {
1868 return EINVAL;
1869 }
1870
1871 psattr->psa_mac_extensions = NULL;
1872 free(psmx);
1873 return 0;
1874 }
1875
1876 int
1877 posix_spawnattr_setcoalition_np(const posix_spawnattr_t * __restrict attr,
1878 uint64_t coalitionid, int type, int role)
1879 {
1880 _posix_spawnattr_t psattr;
1881 struct _posix_spawn_coalition_info *coal_info;
1882
1883 if (attr == NULL || *attr == NULL) {
1884 return EINVAL;
1885 }
1886 if (type < 0 || type > COALITION_TYPE_MAX) {
1887 return EINVAL;
1888 }
1889
1890 psattr = *(_posix_spawnattr_t *)attr;
1891
1892 coal_info = psattr->psa_coalition_info;
1893 if (!coal_info) {
1894 coal_info = (struct _posix_spawn_coalition_info *)malloc(sizeof(*coal_info));
1895 if (!coal_info) {
1896 return ENOMEM;
1897 }
1898 memset(coal_info, 0, sizeof(*coal_info));
1899 psattr->psa_coalition_info = coal_info;
1900 }
1901
1902 coal_info->psci_info[type].psci_id = coalitionid;
1903 coal_info->psci_info[type].psci_role = role;
1904
1905 return 0;
1906 }
1907
1908
1909 int
1910 posix_spawnattr_set_qos_clamp_np(const posix_spawnattr_t * __restrict attr, uint64_t qos_clamp)
1911 {
1912 _posix_spawnattr_t psattr;
1913
1914 if (attr == NULL || *attr == NULL) {
1915 return EINVAL;
1916 }
1917
1918 if (qos_clamp >= POSIX_SPAWN_PROC_CLAMP_LAST) {
1919 return EINVAL;
1920 }
1921
1922 psattr = *(_posix_spawnattr_t *)attr;
1923 psattr->psa_qos_clamp = qos_clamp;
1924
1925 return 0;
1926 }
1927
1928 int
1929 posix_spawnattr_get_qos_clamp_np(const posix_spawnattr_t * __restrict attr, uint64_t * __restrict qos_clampp)
1930 {
1931 _posix_spawnattr_t psattr;
1932
1933 if (attr == NULL || *attr == NULL) {
1934 return EINVAL;
1935 }
1936
1937 psattr = *(_posix_spawnattr_t *)attr;
1938 *qos_clampp = psattr->psa_qos_clamp;
1939
1940 return 0;
1941 }
1942
1943 int
1944 posix_spawnattr_set_darwin_role_np(const posix_spawnattr_t * __restrict attr, uint64_t darwin_role)
1945 {
1946 _posix_spawnattr_t psattr;
1947
1948 if (attr == NULL || *attr == NULL) {
1949 return EINVAL;
1950 }
1951
1952 psattr = *(_posix_spawnattr_t *)attr;
1953 psattr->psa_darwin_role = darwin_role;
1954
1955 return 0;
1956 }
1957
1958 int
1959 posix_spawnattr_get_darwin_role_np(const posix_spawnattr_t * __restrict attr, uint64_t * __restrict darwin_rolep)
1960 {
1961 _posix_spawnattr_t psattr;
1962
1963 if (attr == NULL || *attr == NULL) {
1964 return EINVAL;
1965 }
1966
1967 psattr = *(_posix_spawnattr_t *)attr;
1968 *darwin_rolep = psattr->psa_darwin_role;
1969
1970 return 0;
1971 }
1972
1973
1974 int
1975 posix_spawnattr_set_persona_np(const posix_spawnattr_t * __restrict attr, uid_t persona_id, uint32_t flags)
1976 {
1977 _posix_spawnattr_t psattr;
1978 struct _posix_spawn_persona_info *persona;
1979
1980 if (attr == NULL || *attr == NULL) {
1981 return EINVAL;
1982 }
1983
1984 if (flags & ~POSIX_SPAWN_PERSONA_ALL_FLAGS) {
1985 return EINVAL;
1986 }
1987
1988 psattr = *(_posix_spawnattr_t *)attr;
1989
1990 persona = psattr->psa_persona_info;
1991 if (!persona) {
1992 persona = (struct _posix_spawn_persona_info *)malloc(sizeof(*persona));
1993 if (!persona) {
1994 return ENOMEM;
1995 }
1996 persona->pspi_uid = 0;
1997 persona->pspi_gid = 0;
1998 persona->pspi_ngroups = 0;
1999 persona->pspi_groups[0] = 0;
2000 persona->pspi_gmuid = 0;
2001
2002 psattr->psa_persona_info = persona;
2003 }
2004
2005 persona->pspi_id = persona_id;
2006 persona->pspi_flags = flags;
2007
2008 return 0;
2009 }
2010
2011 int
2012 posix_spawnattr_set_persona_uid_np(const posix_spawnattr_t * __restrict attr, uid_t uid)
2013 {
2014 _posix_spawnattr_t psattr;
2015 struct _posix_spawn_persona_info *persona;
2016
2017 if (attr == NULL || *attr == NULL) {
2018 return EINVAL;
2019 }
2020
2021 psattr = *(_posix_spawnattr_t *)attr;
2022 persona = psattr->psa_persona_info;
2023 if (!persona) {
2024 return EINVAL;
2025 }
2026
2027 if (!(persona->pspi_flags & (POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE | POSIX_SPAWN_PERSONA_FLAGS_VERIFY))) {
2028 return EINVAL;
2029 }
2030
2031 persona->pspi_uid = uid;
2032
2033 persona->pspi_flags |= POSIX_SPAWN_PERSONA_UID;
2034
2035 return 0;
2036 }
2037
2038 int
2039 posix_spawnattr_set_persona_gid_np(const posix_spawnattr_t * __restrict attr, gid_t gid)
2040 {
2041 _posix_spawnattr_t psattr;
2042 struct _posix_spawn_persona_info *persona;
2043
2044 if (attr == NULL || *attr == NULL) {
2045 return EINVAL;
2046 }
2047
2048 psattr = *(_posix_spawnattr_t *)attr;
2049 persona = psattr->psa_persona_info;
2050 if (!persona) {
2051 return EINVAL;
2052 }
2053
2054 if (!(persona->pspi_flags & (POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE | POSIX_SPAWN_PERSONA_FLAGS_VERIFY))) {
2055 return EINVAL;
2056 }
2057
2058 persona->pspi_gid = gid;
2059
2060 persona->pspi_flags |= POSIX_SPAWN_PERSONA_GID;
2061
2062 return 0;
2063 }
2064
2065 int
2066 posix_spawnattr_set_persona_groups_np(const posix_spawnattr_t * __restrict attr, int ngroups, gid_t *gidarray, uid_t gmuid)
2067 {
2068 _posix_spawnattr_t psattr;
2069 struct _posix_spawn_persona_info *persona;
2070
2071 if (attr == NULL || *attr == NULL) {
2072 return EINVAL;
2073 }
2074
2075 if (gidarray == NULL) {
2076 return EINVAL;
2077 }
2078
2079 if (ngroups > NGROUPS || ngroups < 0) {
2080 return EINVAL;
2081 }
2082
2083 psattr = *(_posix_spawnattr_t *)attr;
2084 persona = psattr->psa_persona_info;
2085 if (!persona) {
2086 return EINVAL;
2087 }
2088
2089 if (!(persona->pspi_flags & (POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE | POSIX_SPAWN_PERSONA_FLAGS_VERIFY))) {
2090 return EINVAL;
2091 }
2092
2093 persona->pspi_ngroups = ngroups;
2094 for (int i = 0; i < ngroups; i++) {
2095 persona->pspi_groups[i] = gidarray[i];
2096 }
2097
2098 persona->pspi_gmuid = gmuid;
2099
2100 persona->pspi_flags |= POSIX_SPAWN_PERSONA_GROUPS;
2101
2102 return 0;
2103 }
2104
2105 int
2106 posix_spawnattr_set_max_addr_np(const posix_spawnattr_t * __restrict attr, uint64_t max_addr)
2107 {
2108 _posix_spawnattr_t psattr;
2109
2110 if (attr == NULL || *attr == NULL) {
2111 return EINVAL;
2112 }
2113
2114 psattr = *(_posix_spawnattr_t *)attr;
2115 psattr->psa_max_addr = max_addr;
2116
2117 return 0;
2118 }
2119
2120 static struct _posix_spawn_posix_cred_info *
2121 _posix_spawnattr_get_posix_creds_info(_posix_spawnattr_t psattr)
2122 {
2123 struct _posix_spawn_posix_cred_info *pspci = psattr->psa_posix_cred_info;
2124
2125 if (pspci == NULL) {
2126 pspci = malloc(sizeof(struct _posix_spawn_posix_cred_info));
2127 if (pspci != NULL) {
2128 pspci->pspci_flags = 0;
2129 pspci->pspci_uid = 0;
2130 pspci->pspci_gid = 0;
2131 pspci->pspci_ngroups = 0;
2132 pspci->pspci_groups[0] = 0;
2133 pspci->pspci_gmuid = 0;
2134 pspci->pspci_login[0] = '\0';
2135 psattr->psa_posix_cred_info = pspci;
2136 }
2137 }
2138 return pspci;
2139 }
2140
2141 int
2142 posix_spawnattr_set_uid_np(const posix_spawnattr_t *attr, uid_t uid)
2143 {
2144 struct _posix_spawn_posix_cred_info *pspci;
2145
2146 if (attr == NULL || *attr == NULL) {
2147 return EINVAL;
2148 }
2149
2150 pspci = _posix_spawnattr_get_posix_creds_info(*(_posix_spawnattr_t *)attr);
2151 if (pspci == NULL) {
2152 return ENOMEM;
2153 }
2154
2155 pspci->pspci_uid = uid;
2156
2157 pspci->pspci_flags |= POSIX_SPAWN_POSIX_CRED_UID;
2158
2159 return 0;
2160 }
2161
2162 int
2163 posix_spawnattr_set_gid_np(const posix_spawnattr_t *attr, gid_t gid)
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_gid = gid;
2177
2178 pspci->pspci_flags |= POSIX_SPAWN_POSIX_CRED_GID;
2179
2180 return 0;
2181 }
2182
2183 int
2184 posix_spawnattr_set_groups_np(const posix_spawnattr_t *attr,
2185 int ngroups, gid_t *gidarray, uid_t gmuid)
2186 {
2187 struct _posix_spawn_posix_cred_info *pspci;
2188
2189 if (attr == NULL || *attr == NULL) {
2190 return EINVAL;
2191 }
2192
2193 if (gidarray == NULL) {
2194 return EINVAL;
2195 }
2196
2197 if (ngroups > NGROUPS || ngroups < 0) {
2198 return EINVAL;
2199 }
2200
2201 pspci = _posix_spawnattr_get_posix_creds_info(*(_posix_spawnattr_t *)attr);
2202 if (pspci == NULL) {
2203 return ENOMEM;
2204 }
2205
2206 pspci->pspci_ngroups = ngroups;
2207 for (int i = 0; i < ngroups; i++) {
2208 pspci->pspci_groups[i] = gidarray[i];
2209 }
2210
2211 pspci->pspci_gmuid = gmuid;
2212
2213 pspci->pspci_flags |= POSIX_SPAWN_POSIX_CRED_GROUPS;
2214
2215 return 0;
2216 }
2217
2218 int
2219 posix_spawnattr_set_login_np(const posix_spawnattr_t *attr, const char *login)
2220 {
2221 struct _posix_spawn_posix_cred_info *pspci;
2222
2223 if (attr == NULL || *attr == NULL) {
2224 return EINVAL;
2225 }
2226
2227 if (strlen(login) > MAXLOGNAME) {
2228 return ERANGE;
2229 }
2230
2231 pspci = _posix_spawnattr_get_posix_creds_info(*(_posix_spawnattr_t *)attr);
2232 if (pspci == NULL) {
2233 return ENOMEM;
2234 }
2235
2236 strlcpy(pspci->pspci_login, login, sizeof(pspci->pspci_login));
2237
2238 pspci->pspci_flags |= POSIX_SPAWN_POSIX_CRED_LOGIN;
2239
2240 return 0;
2241 }
2242
2243 /*
2244 * posix_spawnattr_set_jetsam_ttr_np
2245 *
2246 * Description: Pass data regarding recent relaunch behavior when jetsammed for the process.
2247 * The recent history is effectively converted into a histogram and the highest
2248 * frequency bucket defines the "type" of the process. The type is passed along
2249 * to the jetsam code as part of psa_jetsam_flags.
2250 *
2251 * Parameters: count Number of entries in the ttrs_millis array
2252 * ttrs_millis Array of raw data for relaunch behavior
2253 *
2254 * Returns: 0 Success
2255 * EINVAL Bad attr pointer or empty data array
2256 */
2257 int
2258 posix_spawnattr_set_jetsam_ttr_np(const posix_spawnattr_t * __restrict attr, uint32_t count, uint32_t *ttrs_millis)
2259 {
2260 _posix_spawnattr_t psattr;
2261
2262 /*
2263 * Define the bucketizing policy which would be used to generate the histogram. These
2264 * values are based on looking at data from various Avg. Joanna runs.
2265 */
2266 static const uint32_t relaunch_buckets_msecs[POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_BUCKETS] = {
2267 5000,
2268 10000,
2269 UINT32_MAX
2270 };
2271 static const uint32_t relaunch_jetsam_flags[POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_BUCKETS] = {
2272 POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_HIGH,
2273 POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_MED,
2274 POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_LOW
2275 };
2276
2277 /* Make sure the attr pointer is valid */
2278 if (attr == NULL || *attr == NULL) {
2279 return EINVAL;
2280 }
2281
2282 /* Make sure the count of entries is non-zero */
2283 if (count == 0) {
2284 return EINVAL;
2285 }
2286
2287 psattr = *(_posix_spawnattr_t *)attr;
2288
2289 /* Generate a histogram based on the relaunch data while maintaining highest frequency bucket info */
2290 int relaunch_histogram[POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_BUCKETS] = {0};
2291 int max_frequency = -1;
2292 int highest_frequency_bucket = -1;
2293
2294 for (uint32_t i = 0; i < count; i++) {
2295 /* For each data point passed in via launchd, find the bucket it lands in */
2296 for (uint32_t bucket = 0; bucket < POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_BUCKETS; bucket++) {
2297 if (ttrs_millis[i] <= relaunch_buckets_msecs[bucket]) {
2298 relaunch_histogram[bucket]++;
2299
2300 /* Check if the bucket is the highest frequency bucket now */
2301 if (relaunch_histogram[bucket] > max_frequency) {
2302 max_frequency = relaunch_histogram[bucket];
2303 highest_frequency_bucket = bucket;
2304 }
2305 break;
2306 }
2307 }
2308 }
2309 psattr->psa_jetsam_flags |= relaunch_jetsam_flags[highest_frequency_bucket];
2310 return 0;
2311 }
2312
2313 /*
2314 * posix_spawn
2315 *
2316 * Description: Create a new process from the process image corresponding to
2317 * the supplied 'path' argument.
2318 *
2319 * Parameters: pid Pointer to pid_t to receive the
2320 * PID of the spawned process, if
2321 * successful and 'pid' != NULL
2322 * path Path of image file to spawn
2323 * file_actions spawn file actions object which
2324 * describes file actions to be
2325 * performed during the spawn
2326 * attrp spawn attributes object which
2327 * describes attributes to be
2328 * applied during the spawn
2329 * argv argument vector array; NULL
2330 * terminated
2331 * envp environment vector array; NULL
2332 * terminated
2333 *
2334 * Returns: 0 Success
2335 * !0 An errno value indicating the
2336 * cause of the failure to spawn
2337 *
2338 * Notes: Unlike other system calls, the return value of this system
2339 * call is expected to either be a 0 or an errno, rather than a
2340 * 0 or a -1, with the 'errno' variable being set.
2341 */
2342 extern int __posix_spawn(pid_t * __restrict, const char * __restrict,
2343 struct _posix_spawn_args_desc *,
2344 char *const argv[__restrict], char *const envp[__restrict]);
2345
2346 int
2347 posix_spawn(pid_t * __restrict pid, const char * __restrict path,
2348 const posix_spawn_file_actions_t *file_actions,
2349 const posix_spawnattr_t * __restrict attrp,
2350 char *const argv[__restrict], char *const envp[__restrict])
2351 {
2352 int saveerrno = errno;
2353 int ret;
2354 /*
2355 * Only do extra work if we have file actions or attributes to push
2356 * down. We use a descriptor to push this information down, since we
2357 * want to have size information, which will let us (1) preallocate a
2358 * single chunk of memory for the copyin(), and (2) allow us to do a
2359 * single copyin() per attributes or file actions as a monlithic block.
2360 *
2361 * Note: A future implementation may attempt to do the same
2362 * thing for the argv/envp data, which could potentially
2363 * result in a performance improvement due to increased
2364 * kernel efficiency, even though it would mean copying
2365 * the data in user space.
2366 */
2367 if ((file_actions != NULL && (*file_actions != NULL) && (*(_posix_spawn_file_actions_t *)file_actions)->psfa_act_count > 0) || attrp != NULL) {
2368 struct _posix_spawn_args_desc ad;
2369
2370 memset(&ad, 0, sizeof(ad));
2371 if (attrp != NULL && *attrp != NULL) {
2372 _posix_spawnattr_t psattr = *(_posix_spawnattr_t *)attrp;
2373 ad.attr_size = sizeof(struct _posix_spawnattr);
2374 ad.attrp = psattr;
2375
2376 if (psattr->psa_ports != NULL) {
2377 size_t psact_size = PS_PORT_ACTIONS_SIZE(psattr->psa_ports->pspa_count);
2378 if (psact_size == 0 && psattr->psa_ports->pspa_count != 0) {
2379 errno = EINVAL;
2380 ret = -1;
2381 goto out;
2382 }
2383 ad.port_actions = psattr->psa_ports;
2384 ad.port_actions_size = psact_size;
2385 }
2386 if (psattr->psa_mac_extensions != NULL) {
2387 size_t macext_size = PS_MAC_EXTENSIONS_SIZE(psattr->psa_mac_extensions->psmx_count);
2388 if (macext_size == 0 && psattr->psa_mac_extensions->psmx_count != 0) {
2389 errno = EINVAL;
2390 ret = -1;
2391 goto out;
2392 }
2393 ad.mac_extensions = psattr->psa_mac_extensions;
2394 ad.mac_extensions_size = macext_size;
2395 }
2396 if (psattr->psa_coalition_info != NULL) {
2397 ad.coal_info_size = sizeof(struct _posix_spawn_coalition_info);
2398 ad.coal_info = psattr->psa_coalition_info;
2399 }
2400 if (psattr->psa_persona_info != NULL) {
2401 ad.persona_info_size = sizeof(struct _posix_spawn_persona_info);
2402 ad.persona_info = psattr->psa_persona_info;
2403 }
2404 if (psattr->psa_posix_cred_info != NULL) {
2405 ad.posix_cred_info_size = sizeof(struct _posix_spawn_posix_cred_info);
2406 ad.posix_cred_info = psattr->psa_posix_cred_info;
2407 }
2408 }
2409 if (file_actions != NULL && *file_actions != NULL) {
2410 _posix_spawn_file_actions_t psactsp =
2411 *(_posix_spawn_file_actions_t *)file_actions;
2412
2413 if (psactsp->psfa_act_count > 0) {
2414 size_t fa_size = PSF_ACTIONS_SIZE(psactsp->psfa_act_count);
2415 if (fa_size == 0 && psactsp->psfa_act_count != 0) {
2416 errno = EINVAL;
2417 ret = -1;
2418 goto out;
2419 }
2420 ad.file_actions_size = fa_size;
2421 ad.file_actions = psactsp;
2422 }
2423 }
2424
2425 ret = __posix_spawn(pid, path, &ad, argv, envp);
2426 } else {
2427 ret = __posix_spawn(pid, path, NULL, argv, envp);
2428 }
2429
2430 out:
2431 if (ret < 0) {
2432 ret = errno;
2433 }
2434 errno = saveerrno;
2435 return ret;
2436 }