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