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