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