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