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