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