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