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