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