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