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