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