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