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