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