xref: /xnu-12377.61.12/bsd/kern/kern_resource.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
1 /*
2  * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
29 /*-
30  * Copyright (c) 1982, 1986, 1991, 1993
31  *	The Regents of the University of California.  All rights reserved.
32  * (c) UNIX System Laboratories, Inc.
33  * All or some portions of this file are derived from material licensed
34  * to the University of California by American Telephone and Telegraph
35  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
36  * the permission of UNIX System Laboratories, Inc.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. All advertising materials mentioning features or use of this software
47  *    must display the following acknowledgement:
48  *	This product includes software developed by the University of
49  *	California, Berkeley and its contributors.
50  * 4. Neither the name of the University nor the names of its contributors
51  *    may be used to endorse or promote products derived from this software
52  *    without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64  * SUCH DAMAGE.
65  *
66  *	@(#)kern_resource.c	8.5 (Berkeley) 1/21/94
67  */
68 /*
69  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
70  * support for mandatory and extensible security protections.  This notice
71  * is included in support of clause 2.2 (b) of the Apple Public License,
72  * Version 2.0.
73  */
74 
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/sysctl.h>
78 #include <sys/kernel.h>
79 #include <sys/file_internal.h>
80 #include <sys/resourcevar.h>
81 #include <sys/malloc.h>
82 #include <sys/proc_internal.h>
83 #include <sys/kauth.h>
84 #include <sys/mount_internal.h>
85 #include <sys/sysproto.h>
86 
87 #include <security/audit/audit.h>
88 
89 #include <machine/vmparam.h>
90 
91 #include <mach/mach_types.h>
92 #include <mach/time_value.h>
93 #include <mach/task.h>
94 #include <mach/task_info.h>
95 #include <mach/vm_map.h>
96 #include <mach/mach_vm.h>
97 #include <mach/thread_act.h>  /* for thread_policy_set( ) */
98 #include <kern/thread.h>
99 #include <kern/policy_internal.h>
100 
101 #include <kern/task.h>
102 #include <kern/clock.h>         /* for absolutetime_to_microtime() */
103 #include <netinet/in.h>         /* for TRAFFIC_MGT_SO_* */
104 #if CONFIG_FREEZE
105 #include <sys/kern_memorystatus_freeze.h> /* for memorystatus_freeze_mark_ui_transition */
106 #endif /* CONFIG_FREEZE */
107 #include <sys/kern_memorystatus_xnu.h> /* for memorystatus_get_proc_is_managed */
108 #include <sys/socketvar.h>      /* for struct socket */
109 #if NECP
110 #include <net/necp.h>
111 #endif /* NECP */
112 
113 #include <vm/vm_map_xnu.h>
114 
115 #include <kern/assert.h>
116 #include <sys/resource.h>
117 #include <sys/resource_private.h>
118 #include <sys/priv.h>
119 #include <IOKit/IOBSD.h>
120 
121 #if CONFIG_MACF
122 #include <security/mac_framework.h>
123 #endif
124 
125 static void proc_limitblock(proc_t p);
126 static void proc_limitunblock(proc_t p);
127 static void proc_limitupdate(proc_t p, bool unblock,
128     void (^update)(struct plimit *plim));
129 
130 static int donice(struct proc *curp, struct proc *chgp, int n);
131 static int dosetrlimit(struct proc *p, u_int which, struct rlimit *limp);
132 static void do_background_socket(struct proc *p, thread_t thread);
133 static int do_background_thread(thread_t thread, int priority);
134 static int do_background_proc(struct proc *curp, struct proc *targetp, int priority);
135 static int proc_set_gpurole(struct proc *curp, struct proc *targetp, int priority);
136 static int proc_get_gpurole(proc_t targetp, int *priority);
137 static int proc_set_darwin_role(proc_t curp, proc_t targetp, int priority);
138 static int proc_get_darwin_role(proc_t curp, proc_t targetp, int *priority);
139 static int proc_set_game_mode(proc_t targetp, int priority);
140 static int proc_get_game_mode(proc_t targetp, int *priority);
141 static int proc_set_carplay_mode(proc_t targetp, int priority);
142 static int proc_get_carplay_mode(proc_t targetp, int *priority);
143 static int proc_set_runaway_mitigation(proc_t targetp, int priority);
144 static int proc_get_runaway_mitigation(proc_t targetp, int *priority);
145 static int get_background_proc(struct proc *curp, struct proc *targetp, int *priority);
146 
147 int fill_task_rusage(task_t task, rusage_info_current *ri);
148 void fill_task_billed_usage(task_t task, rusage_info_current *ri);
149 int fill_task_io_rusage(task_t task, rusage_info_current *ri);
150 int fill_task_qos_rusage(task_t task, rusage_info_current *ri);
151 uint64_t get_task_logical_writes(task_t task, bool external);
152 
153 rlim_t maxdmap = MAXDSIZ;       /* XXX */
154 rlim_t maxsmap = MAXSSIZ - PAGE_MAX_SIZE;       /* XXX */
155 
156 /* For plimit reference count */
157 os_refgrp_decl(, rlimit_refgrp, "plimit_refcnt", NULL);
158 
159 static KALLOC_TYPE_DEFINE(plimit_zone, struct plimit, KT_DEFAULT);
160 
161 /*
162  * Limits on the number of open files per process, and the number
163  * of child processes per process.
164  *
165  * Note: would be in kern/subr_param.c in FreeBSD.
166  */
167 __private_extern__ int maxfilesperproc = OPEN_MAX;              /* per-proc open files limit */
168 
169 SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, CTLFLAG_RW | CTLFLAG_LOCKED,
170     &maxprocperuid, 0, "Maximum processes allowed per userid" );
171 
172 SYSCTL_INT(_kern, KERN_MAXFILESPERPROC, maxfilesperproc, CTLFLAG_RW | CTLFLAG_LOCKED,
173     &maxfilesperproc, 0, "Maximum files allowed open per process" );
174 
175 /* Args and fn for proc_iteration callback used in setpriority */
176 struct puser_nice_args {
177 	proc_t curp;
178 	int     prio;
179 	id_t    who;
180 	int *   foundp;
181 	int *   errorp;
182 };
183 static int puser_donice_callback(proc_t p, void * arg);
184 
185 
186 /* Args and fn for proc_iteration callback used in setpriority */
187 struct ppgrp_nice_args {
188 	proc_t curp;
189 	int     prio;
190 	int *   foundp;
191 	int *   errorp;
192 };
193 static int ppgrp_donice_callback(proc_t p, void * arg);
194 
195 /*
196  * Resource controls and accounting.
197  */
198 int
getpriority(struct proc * curp,struct getpriority_args * uap,int32_t * retval)199 getpriority(struct proc *curp, struct getpriority_args *uap, int32_t *retval)
200 {
201 	struct proc *p;
202 	int low = PRIO_MAX + 1;
203 	kauth_cred_t my_cred;
204 	int refheld = 0;
205 	int error = 0;
206 
207 	/* would also test (uap->who < 0), but id_t is unsigned */
208 	if (uap->who > 0x7fffffff) {
209 		return EINVAL;
210 	}
211 
212 	switch (uap->which) {
213 	case PRIO_PROCESS:
214 		if (uap->who == 0) {
215 			p = curp;
216 			low = p->p_nice;
217 		} else {
218 			p = proc_find(uap->who);
219 			if (p == 0) {
220 				break;
221 			}
222 			low = p->p_nice;
223 			proc_rele(p);
224 		}
225 		break;
226 
227 	case PRIO_PGRP: {
228 		struct pgrp *pg = PGRP_NULL;
229 
230 		if (uap->who == 0) {
231 			/* returns the pgrp to ref */
232 			pg = proc_pgrp(curp, NULL);
233 		} else if ((pg = pgrp_find(uap->who)) == PGRP_NULL) {
234 			break;
235 		}
236 		/* No need for iteration as it is a simple scan */
237 		pgrp_lock(pg);
238 		PGMEMBERS_FOREACH(pg, p) {
239 			if (p->p_nice < low) {
240 				low = p->p_nice;
241 			}
242 		}
243 		pgrp_unlock(pg);
244 		pgrp_rele(pg);
245 		break;
246 	}
247 
248 	case PRIO_USER:
249 		if (uap->who == 0) {
250 			uap->who = kauth_cred_getuid(kauth_cred_get());
251 		}
252 
253 		proc_list_lock();
254 
255 		for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
256 			my_cred = kauth_cred_proc_ref(p);
257 			if (kauth_cred_getuid(my_cred) == uap->who &&
258 			    p->p_nice < low) {
259 				low = p->p_nice;
260 			}
261 			kauth_cred_unref(&my_cred);
262 		}
263 
264 		proc_list_unlock();
265 
266 		break;
267 
268 	case PRIO_DARWIN_THREAD:
269 		/* we currently only support the current thread */
270 		if (uap->who != 0) {
271 			return EINVAL;
272 		}
273 
274 		low = proc_get_thread_policy(current_thread(), TASK_POLICY_INTERNAL, TASK_POLICY_DARWIN_BG);
275 
276 		break;
277 
278 	case PRIO_DARWIN_PROCESS:
279 		if (uap->who == 0) {
280 			p = curp;
281 		} else {
282 			p = proc_find(uap->who);
283 			if (p == PROC_NULL) {
284 				break;
285 			}
286 			refheld = 1;
287 		}
288 
289 		error = get_background_proc(curp, p, &low);
290 
291 		if (refheld) {
292 			proc_rele(p);
293 		}
294 		if (error) {
295 			return error;
296 		}
297 		break;
298 
299 	case PRIO_DARWIN_ROLE:
300 		if (uap->who == 0) {
301 			p = curp;
302 		} else {
303 			p = proc_find(uap->who);
304 			if (p == PROC_NULL) {
305 				break;
306 			}
307 			refheld = 1;
308 		}
309 
310 		error = proc_get_darwin_role(curp, p, &low);
311 
312 		if (refheld) {
313 			proc_rele(p);
314 		}
315 		if (error) {
316 			return error;
317 		}
318 		break;
319 
320 	case PRIO_DARWIN_GAME_MODE:
321 		if (uap->who == 0) {
322 			p = curp;
323 		} else {
324 			p = proc_find(uap->who);
325 			if (p == PROC_NULL) {
326 				break;
327 			}
328 			refheld = 1;
329 		}
330 
331 
332 		error = proc_get_game_mode(p, &low);
333 
334 		if (refheld) {
335 			proc_rele(p);
336 		}
337 		if (error) {
338 			return error;
339 		}
340 		break;
341 
342 	case PRIO_DARWIN_CARPLAY_MODE:
343 		if (uap->who == 0) {
344 			p = curp;
345 		} else {
346 			p = proc_find(uap->who);
347 			if (p == PROC_NULL) {
348 				break;
349 			}
350 			refheld = 1;
351 		}
352 
353 
354 		error = proc_get_carplay_mode(p, &low);
355 
356 		if (refheld) {
357 			proc_rele(p);
358 		}
359 		if (error) {
360 			return error;
361 		}
362 		break;
363 
364 	case PRIO_DARWIN_GPU:
365 		if (uap->who == 0) {
366 			p = curp;
367 		} else {
368 			p = proc_find(uap->who);
369 			if (p == PROC_NULL) {
370 				break;
371 			}
372 			refheld = 1;
373 		}
374 
375 
376 		error = proc_get_gpurole(p, &low);
377 
378 		if (refheld) {
379 			proc_rele(p);
380 		}
381 		if (error) {
382 			return error;
383 		}
384 		break;
385 
386 	case PRIO_DARWIN_RUNAWAY_MITIGATION:
387 		if (uap->who == 0) {
388 			p = curp;
389 		} else {
390 			p = proc_find(uap->who);
391 			if (p == PROC_NULL) {
392 				break;
393 			}
394 			refheld = 1;
395 		}
396 
397 
398 		error = proc_get_runaway_mitigation(p, &low);
399 
400 		if (refheld) {
401 			proc_rele(p);
402 		}
403 		if (error) {
404 			return error;
405 		}
406 		break;
407 
408 	default:
409 		return EINVAL;
410 	}
411 	if (low == PRIO_MAX + 1) {
412 		return ESRCH;
413 	}
414 	*retval = low;
415 	return 0;
416 }
417 
418 /* call back function used for proc iteration in PRIO_USER */
419 static int
puser_donice_callback(proc_t p,void * arg)420 puser_donice_callback(proc_t p, void * arg)
421 {
422 	int error, n;
423 	struct puser_nice_args * pun = (struct puser_nice_args *)arg;
424 	kauth_cred_t my_cred;
425 
426 	my_cred = kauth_cred_proc_ref(p);
427 	if (kauth_cred_getuid(my_cred) == pun->who) {
428 		error = donice(pun->curp, p, pun->prio);
429 		if (pun->errorp != NULL) {
430 			*pun->errorp = error;
431 		}
432 		if (pun->foundp != NULL) {
433 			n = *pun->foundp;
434 			*pun->foundp = n + 1;
435 		}
436 	}
437 	kauth_cred_unref(&my_cred);
438 
439 	return PROC_RETURNED;
440 }
441 
442 /* call back function used for proc iteration in PRIO_PGRP */
443 static int
ppgrp_donice_callback(proc_t p,void * arg)444 ppgrp_donice_callback(proc_t p, void * arg)
445 {
446 	int error;
447 	struct ppgrp_nice_args * pun = (struct ppgrp_nice_args *)arg;
448 	int n;
449 
450 	error = donice(pun->curp, p, pun->prio);
451 	if (pun->errorp != NULL) {
452 		*pun->errorp = error;
453 	}
454 	if (pun->foundp != NULL) {
455 		n = *pun->foundp;
456 		*pun->foundp = n + 1;
457 	}
458 
459 	return PROC_RETURNED;
460 }
461 
462 /*
463  * Returns:	0			Success
464  *		EINVAL
465  *		ESRCH
466  *	donice:EPERM
467  *	donice:EACCES
468  */
469 /* ARGSUSED */
470 int
setpriority(struct proc * curp,struct setpriority_args * uap,int32_t * retval)471 setpriority(struct proc *curp, struct setpriority_args *uap, int32_t *retval)
472 {
473 	struct proc *p;
474 	int found = 0, error = 0;
475 	int refheld = 0;
476 
477 	AUDIT_ARG(cmd, uap->which);
478 	AUDIT_ARG(owner, uap->who, 0);
479 	AUDIT_ARG(value32, uap->prio);
480 
481 	/* would also test (uap->who < 0), but id_t is unsigned */
482 	if (uap->who > 0x7fffffff) {
483 		return EINVAL;
484 	}
485 
486 	switch (uap->which) {
487 	case PRIO_PROCESS:
488 		if (uap->who == 0) {
489 			p = curp;
490 		} else {
491 			p = proc_find(uap->who);
492 			if (p == 0) {
493 				break;
494 			}
495 			refheld = 1;
496 		}
497 		error = donice(curp, p, uap->prio);
498 		found++;
499 		if (refheld != 0) {
500 			proc_rele(p);
501 		}
502 		break;
503 
504 	case PRIO_PGRP: {
505 		struct pgrp *pg = PGRP_NULL;
506 		struct ppgrp_nice_args ppgrp;
507 
508 		if (uap->who == 0) {
509 			pg = proc_pgrp(curp, NULL);
510 		} else if ((pg = pgrp_find(uap->who)) == PGRP_NULL) {
511 			break;
512 		}
513 
514 		ppgrp.curp = curp;
515 		ppgrp.prio = uap->prio;
516 		ppgrp.foundp = &found;
517 		ppgrp.errorp = &error;
518 
519 		pgrp_iterate(pg, ppgrp_donice_callback, (void *)&ppgrp, NULL);
520 		pgrp_rele(pg);
521 
522 		break;
523 	}
524 
525 	case PRIO_USER: {
526 		struct puser_nice_args punice;
527 
528 		if (uap->who == 0) {
529 			uap->who = kauth_cred_getuid(kauth_cred_get());
530 		}
531 
532 		punice.curp = curp;
533 		punice.prio = uap->prio;
534 		punice.who = uap->who;
535 		punice.foundp = &found;
536 		error = 0;
537 		punice.errorp = &error;
538 		proc_iterate(PROC_ALLPROCLIST, puser_donice_callback, (void *)&punice, NULL, NULL);
539 
540 		break;
541 	}
542 
543 	case PRIO_DARWIN_THREAD: {
544 		/* we currently only support the current thread */
545 		if (uap->who != 0) {
546 			return EINVAL;
547 		}
548 
549 		error = do_background_thread(current_thread(), uap->prio);
550 		found++;
551 		break;
552 	}
553 
554 	case PRIO_DARWIN_PROCESS: {
555 		if (uap->who == 0) {
556 			p = curp;
557 		} else {
558 			p = proc_find(uap->who);
559 			if (p == 0) {
560 				break;
561 			}
562 			refheld = 1;
563 		}
564 
565 		error = do_background_proc(curp, p, uap->prio);
566 
567 		found++;
568 		if (refheld != 0) {
569 			proc_rele(p);
570 		}
571 		break;
572 	}
573 
574 	case PRIO_DARWIN_GPU: {
575 		if (uap->who == 0) {
576 			return EINVAL;
577 		}
578 
579 		p = proc_find(uap->who);
580 		if (p == PROC_NULL) {
581 			break;
582 		}
583 
584 		error = proc_set_gpurole(curp, p, uap->prio);
585 
586 		found++;
587 		proc_rele(p);
588 		break;
589 	}
590 
591 	case PRIO_DARWIN_ROLE: {
592 		if (uap->who == 0) {
593 			p = curp;
594 		} else {
595 			p = proc_find(uap->who);
596 			if (p == PROC_NULL) {
597 				break;
598 			}
599 			refheld = 1;
600 		}
601 
602 		error = proc_set_darwin_role(curp, p, uap->prio);
603 
604 		found++;
605 		if (refheld != 0) {
606 			proc_rele(p);
607 		}
608 		break;
609 	}
610 
611 	case PRIO_DARWIN_GAME_MODE: {
612 		if (uap->who == 0) {
613 			p = curp;
614 		} else {
615 			p = proc_find(uap->who);
616 			if (p == PROC_NULL) {
617 				break;
618 			}
619 			refheld = 1;
620 		}
621 
622 
623 		error = proc_set_game_mode(p, uap->prio);
624 
625 		found++;
626 		if (refheld != 0) {
627 			proc_rele(p);
628 		}
629 		break;
630 	}
631 
632 	case PRIO_DARWIN_CARPLAY_MODE: {
633 		if (uap->who == 0) {
634 			p = curp;
635 		} else {
636 			p = proc_find(uap->who);
637 			if (p == PROC_NULL) {
638 				break;
639 			}
640 			refheld = 1;
641 		}
642 
643 		error = proc_set_carplay_mode(p, uap->prio);
644 
645 		found++;
646 		if (refheld != 0) {
647 			proc_rele(p);
648 		}
649 		break;
650 	}
651 
652 	case PRIO_DARWIN_RUNAWAY_MITIGATION: {
653 		if (uap->who == 0) {
654 			p = curp;
655 		} else {
656 			p = proc_find(uap->who);
657 			if (p == PROC_NULL) {
658 				break;
659 			}
660 			refheld = 1;
661 		}
662 
663 		error = proc_set_runaway_mitigation(p, uap->prio);
664 
665 		found++;
666 		if (refheld != 0) {
667 			proc_rele(p);
668 		}
669 		break;
670 	}
671 
672 	default:
673 		return EINVAL;
674 	}
675 	if (found == 0) {
676 		return ESRCH;
677 	}
678 	if (error == EIDRM) {
679 		*retval = -2;
680 		error = 0;
681 	}
682 	return error;
683 }
684 
685 
686 /*
687  * Returns:	0			Success
688  *		EPERM
689  *		EACCES
690  *	mac_check_proc_sched:???
691  */
692 static int
donice(struct proc * curp,struct proc * chgp,int n)693 donice(struct proc *curp, struct proc *chgp, int n)
694 {
695 	int error = 0;
696 	kauth_cred_t ucred;
697 	kauth_cred_t my_cred;
698 
699 	ucred = kauth_cred_proc_ref(curp);
700 	my_cred = kauth_cred_proc_ref(chgp);
701 
702 	if (suser(ucred, NULL) && kauth_cred_getruid(ucred) &&
703 	    kauth_cred_getuid(ucred) != kauth_cred_getuid(my_cred) &&
704 	    kauth_cred_getruid(ucred) != kauth_cred_getuid(my_cred)) {
705 		error = EPERM;
706 		goto out;
707 	}
708 	if (n > PRIO_MAX) {
709 		n = PRIO_MAX;
710 	}
711 	if (n < PRIO_MIN) {
712 		n = PRIO_MIN;
713 	}
714 	if (n < chgp->p_nice && suser(ucred, &curp->p_acflag)) {
715 		error = EACCES;
716 		goto out;
717 	}
718 #if CONFIG_MACF
719 	error = mac_proc_check_sched(curp, chgp);
720 	if (error) {
721 		goto out;
722 	}
723 #endif
724 	proc_lock(chgp);
725 	chgp->p_nice = (char)n;
726 	proc_unlock(chgp);
727 	(void)resetpriority(chgp);
728 out:
729 	kauth_cred_unref(&ucred);
730 	kauth_cred_unref(&my_cred);
731 	return error;
732 }
733 
734 #define SET_GPU_ROLE_ENTITLEMENT "com.apple.private.set-gpu-role"
735 
736 static int
proc_set_gpurole(struct proc * curp,struct proc * targetp,int priority)737 proc_set_gpurole(struct proc *curp, struct proc *targetp, int priority)
738 {
739 	int error = 0;
740 	kauth_cred_t ucred;
741 	kauth_cred_t target_cred;
742 
743 	ucred = kauth_cred_get();
744 	target_cred = kauth_cred_proc_ref(targetp);
745 
746 	boolean_t entitled = FALSE;
747 	entitled = IOCurrentTaskHasEntitlement(SET_GPU_ROLE_ENTITLEMENT);
748 	if (!entitled) {
749 		error = EPERM;
750 		goto out;
751 	}
752 
753 	if (!kauth_cred_issuser(ucred) && kauth_cred_getruid(ucred) &&
754 	    kauth_cred_getuid(ucred) != kauth_cred_getuid(target_cred) &&
755 	    kauth_cred_getruid(ucred) != kauth_cred_getuid(target_cred)) {
756 		error = EPERM;
757 		goto out;
758 	}
759 
760 	if (curp == targetp) {
761 		error = EPERM;
762 		goto out;
763 	}
764 
765 #if CONFIG_MACF
766 	error = mac_proc_check_sched(curp, targetp);
767 	if (error) {
768 		goto out;
769 	}
770 #endif
771 
772 	switch (priority) {
773 	case PRIO_DARWIN_GPU_UNKNOWN:
774 	case PRIO_DARWIN_GPU_ALLOW:
775 	case PRIO_DARWIN_GPU_DENY:
776 	case PRIO_DARWIN_GPU_BACKGROUND:
777 	case PRIO_DARWIN_GPU_UTILITY:
778 	case PRIO_DARWIN_GPU_UI_NON_FOCAL:
779 	case PRIO_DARWIN_GPU_UI:
780 	case PRIO_DARWIN_GPU_UI_FOCAL:
781 		task_set_gpu_role(proc_task(targetp),
782 		    (darwin_gpu_role_t)priority);
783 		break;
784 	default:
785 		error = EINVAL;
786 		goto out;
787 	}
788 
789 out:
790 	kauth_cred_unref(&target_cred);
791 	return error;
792 }
793 
794 static int
proc_get_gpurole(proc_t targetp,int * priority)795 proc_get_gpurole(proc_t targetp, int *priority)
796 {
797 	int error = 0;
798 
799 	kauth_cred_t ucred, target_cred;
800 
801 	ucred = kauth_cred_get();
802 	target_cred = kauth_cred_proc_ref(targetp);
803 
804 	boolean_t entitled = FALSE;
805 	entitled = IOCurrentTaskHasEntitlement(SET_GPU_ROLE_ENTITLEMENT);
806 
807 	/* Root is allowed to get without entitlement */
808 	if (!kauth_cred_issuser(ucred) && !entitled) {
809 		error = EPERM;
810 		goto out;
811 	}
812 
813 	/* Even with entitlement, non-root is only alllowed to see same-user */
814 	if (!kauth_cred_issuser(ucred) &&
815 	    kauth_cred_getuid(ucred) != kauth_cred_getuid(target_cred)) {
816 		error = EPERM;
817 		goto out;
818 	}
819 
820 	darwin_gpu_role_t gpurole = task_get_gpu_role(proc_task(targetp));
821 
822 	*priority = gpurole;
823 
824 out:
825 	kauth_cred_unref(&target_cred);
826 	return error;
827 }
828 
829 
830 static int
proc_set_darwin_role(proc_t curp,proc_t targetp,int priority)831 proc_set_darwin_role(proc_t curp, proc_t targetp, int priority)
832 {
833 	int error = 0;
834 	uint32_t flagsp = 0;
835 
836 	kauth_cred_t ucred, target_cred;
837 
838 	ucred = kauth_cred_get();
839 	target_cred = kauth_cred_proc_ref(targetp);
840 
841 	if (!kauth_cred_issuser(ucred) && kauth_cred_getruid(ucred) &&
842 	    kauth_cred_getuid(ucred) != kauth_cred_getuid(target_cred) &&
843 	    kauth_cred_getruid(ucred) != kauth_cred_getuid(target_cred)) {
844 		if (priv_check_cred(ucred, PRIV_SETPRIORITY_DARWIN_ROLE, 0) != 0) {
845 			error = EPERM;
846 			goto out;
847 		}
848 	}
849 
850 	if (curp != targetp) {
851 #if CONFIG_MACF
852 		if ((error = mac_proc_check_sched(curp, targetp))) {
853 			goto out;
854 		}
855 #endif
856 	}
857 
858 	proc_get_darwinbgstate(proc_task(targetp), &flagsp);
859 	if ((flagsp & PROC_FLAG_APPLICATION) != PROC_FLAG_APPLICATION) {
860 		error = ENOTSUP;
861 		goto out;
862 	}
863 
864 	task_role_t role = TASK_UNSPECIFIED;
865 
866 	if ((error = proc_darwin_role_to_task_role(priority, &role))) {
867 		goto out;
868 	}
869 
870 	proc_set_task_policy(proc_task(targetp), TASK_POLICY_ATTRIBUTE,
871 	    TASK_POLICY_ROLE, role);
872 
873 #if CONFIG_FREEZE
874 	if (priority == PRIO_DARWIN_ROLE_UI_FOCAL || priority == PRIO_DARWIN_ROLE_UI || priority == PRIO_DARWIN_ROLE_UI_NON_FOCAL) {
875 		memorystatus_freezer_mark_ui_transition(targetp);
876 	}
877 #endif /* CONFIG_FREEZE */
878 
879 out:
880 	kauth_cred_unref(&target_cred);
881 	return error;
882 }
883 
884 static int
proc_get_darwin_role(proc_t curp,proc_t targetp,int * priority)885 proc_get_darwin_role(proc_t curp, proc_t targetp, int *priority)
886 {
887 	int error = 0;
888 	int role = 0;
889 
890 	kauth_cred_t ucred, target_cred;
891 
892 	ucred = kauth_cred_get();
893 	target_cred = kauth_cred_proc_ref(targetp);
894 
895 	if (!kauth_cred_issuser(ucred) && kauth_cred_getruid(ucred) &&
896 	    kauth_cred_getuid(ucred) != kauth_cred_getuid(target_cred) &&
897 	    kauth_cred_getruid(ucred) != kauth_cred_getuid(target_cred)) {
898 		error = EPERM;
899 		goto out;
900 	}
901 
902 	if (curp != targetp) {
903 #if CONFIG_MACF
904 		if ((error = mac_proc_check_sched(curp, targetp))) {
905 			goto out;
906 		}
907 #endif
908 	}
909 
910 	role = proc_get_task_policy(proc_task(targetp), TASK_POLICY_ATTRIBUTE, TASK_POLICY_ROLE);
911 
912 	*priority = proc_task_role_to_darwin_role(role);
913 
914 out:
915 	kauth_cred_unref(&target_cred);
916 	return error;
917 }
918 
919 #define SET_GAME_MODE_ENTITLEMENT "com.apple.private.set-game-mode"
920 
921 static int
proc_set_game_mode(proc_t targetp,int priority)922 proc_set_game_mode(proc_t targetp, int priority)
923 {
924 	int error = 0;
925 
926 	kauth_cred_t ucred, target_cred;
927 
928 	ucred = kauth_cred_get();
929 	target_cred = kauth_cred_proc_ref(targetp);
930 
931 	boolean_t entitled = FALSE;
932 	entitled = IOCurrentTaskHasEntitlement(SET_GAME_MODE_ENTITLEMENT);
933 	if (!entitled) {
934 		error = EPERM;
935 		goto out;
936 	}
937 
938 	/* Even with entitlement, non-root is only alllowed to set same-user */
939 	if (!kauth_cred_issuser(ucred) &&
940 	    kauth_cred_getuid(ucred) != kauth_cred_getuid(target_cred)) {
941 		error = EPERM;
942 		goto out;
943 	}
944 
945 	switch (priority) {
946 	case PRIO_DARWIN_GAME_MODE_OFF:
947 		task_set_game_mode(proc_task(targetp), false);
948 		break;
949 	case PRIO_DARWIN_GAME_MODE_ON:
950 		task_set_game_mode(proc_task(targetp), true);
951 		break;
952 	default:
953 		error = EINVAL;
954 		goto out;
955 	}
956 
957 out:
958 	kauth_cred_unref(&target_cred);
959 	return error;
960 }
961 
962 static int
proc_get_game_mode(proc_t targetp,int * priority)963 proc_get_game_mode(proc_t targetp, int *priority)
964 {
965 	int error = 0;
966 
967 	kauth_cred_t ucred, target_cred;
968 
969 	ucred = kauth_cred_get();
970 	target_cred = kauth_cred_proc_ref(targetp);
971 
972 	boolean_t entitled = FALSE;
973 	entitled = IOCurrentTaskHasEntitlement(SET_GAME_MODE_ENTITLEMENT);
974 
975 	/* Root is allowed to get without entitlement */
976 	if (!kauth_cred_issuser(ucred) && !entitled) {
977 		error = EPERM;
978 		goto out;
979 	}
980 
981 	/* Even with entitlement, non-root is only alllowed to see same-user */
982 	if (!kauth_cred_issuser(ucred) &&
983 	    kauth_cred_getuid(ucred) != kauth_cred_getuid(target_cred)) {
984 		error = EPERM;
985 		goto out;
986 	}
987 
988 	if (task_get_game_mode(proc_task(targetp))) {
989 		*priority = PRIO_DARWIN_GAME_MODE_ON;
990 	} else {
991 		*priority = PRIO_DARWIN_GAME_MODE_OFF;
992 	}
993 
994 out:
995 	kauth_cred_unref(&target_cred);
996 	return error;
997 }
998 
999 #define SET_CARPLAY_MODE_ENTITLEMENT "com.apple.private.set-carplay-mode"
1000 
1001 static int
proc_set_carplay_mode(proc_t targetp,int priority)1002 proc_set_carplay_mode(proc_t targetp, int priority)
1003 {
1004 	int error = 0;
1005 
1006 	kauth_cred_t ucred, target_cred;
1007 
1008 	ucred = kauth_cred_get();
1009 	target_cred = kauth_cred_proc_ref(targetp);
1010 
1011 	boolean_t entitled = FALSE;
1012 	entitled = IOCurrentTaskHasEntitlement(SET_CARPLAY_MODE_ENTITLEMENT);
1013 	if (!entitled) {
1014 		error = EPERM;
1015 		goto out;
1016 	}
1017 
1018 	/* Even with entitlement, non-root is only alllowed to set same-user */
1019 	if (!kauth_cred_issuser(ucred) &&
1020 	    kauth_cred_getuid(ucred) != kauth_cred_getuid(target_cred)) {
1021 		error = EPERM;
1022 		goto out;
1023 	}
1024 
1025 	switch (priority) {
1026 	case PRIO_DARWIN_CARPLAY_MODE_OFF:
1027 		task_set_carplay_mode(proc_task(targetp), false);
1028 		break;
1029 	case PRIO_DARWIN_CARPLAY_MODE_ON:
1030 		task_set_carplay_mode(proc_task(targetp), true);
1031 		break;
1032 	default:
1033 		error = EINVAL;
1034 		goto out;
1035 	}
1036 
1037 out:
1038 	kauth_cred_unref(&target_cred);
1039 	return error;
1040 }
1041 
1042 static int
proc_get_carplay_mode(proc_t targetp,int * priority)1043 proc_get_carplay_mode(proc_t targetp, int *priority)
1044 {
1045 	int error = 0;
1046 
1047 	kauth_cred_t ucred, target_cred;
1048 
1049 	ucred = kauth_cred_get();
1050 	target_cred = kauth_cred_proc_ref(targetp);
1051 
1052 	boolean_t entitled = FALSE;
1053 	entitled = IOCurrentTaskHasEntitlement(SET_CARPLAY_MODE_ENTITLEMENT);
1054 
1055 	/* Root is allowed to get without entitlement */
1056 	if (!kauth_cred_issuser(ucred) && !entitled) {
1057 		error = EPERM;
1058 		goto out;
1059 	}
1060 
1061 	/* Even with entitlement, non-root is only alllowed to see same-user */
1062 	if (!kauth_cred_issuser(ucred) &&
1063 	    kauth_cred_getuid(ucred) != kauth_cred_getuid(target_cred)) {
1064 		error = EPERM;
1065 		goto out;
1066 	}
1067 
1068 	if (task_get_carplay_mode(proc_task(targetp))) {
1069 		*priority = PRIO_DARWIN_CARPLAY_MODE_ON;
1070 	} else {
1071 		*priority = PRIO_DARWIN_CARPLAY_MODE_OFF;
1072 	}
1073 
1074 out:
1075 	kauth_cred_unref(&target_cred);
1076 	return error;
1077 }
1078 
1079 #define RUNAWAY_MITIGATION_ENTITLEMENT "com.apple.private.runaway-mitigation"
1080 
1081 /* Boot arg to allow RunningBoard-managed processes to be mitigated */
1082 static TUNABLE(bool, allow_managed_mitigation, "allow_managed_mitigation", false);
1083 
1084 static int
proc_set_runaway_mitigation(proc_t targetp,int priority)1085 proc_set_runaway_mitigation(proc_t targetp, int priority)
1086 {
1087 	int error = 0;
1088 
1089 	kauth_cred_t ucred, target_cred;
1090 
1091 	ucred = kauth_cred_get();
1092 	target_cred = kauth_cred_proc_ref(targetp);
1093 
1094 	boolean_t entitled = FALSE;
1095 	entitled = IOCurrentTaskHasEntitlement(RUNAWAY_MITIGATION_ENTITLEMENT);
1096 	if (!entitled) {
1097 		error = EPERM;
1098 		goto out;
1099 	}
1100 
1101 	/* Even with entitlement, non-root is only alllowed to set same-user */
1102 	if (!kauth_cred_issuser(ucred) &&
1103 	    kauth_cred_getuid(ucred) != kauth_cred_getuid(target_cred)) {
1104 		error = EPERM;
1105 		goto out;
1106 	}
1107 
1108 	switch (priority) {
1109 	case PRIO_DARWIN_RUNAWAY_MITIGATION_OFF:
1110 		printf("%s[%d] disabling runaway mitigation on %s[%d]\n",
1111 		    proc_best_name(current_proc()), proc_selfpid(),
1112 		    proc_best_name(targetp), proc_getpid(targetp));
1113 
1114 		proc_set_task_policy(proc_task(targetp), TASK_POLICY_ATTRIBUTE,
1115 		    TASK_POLICY_RUNAWAY_MITIGATION, TASK_POLICY_DISABLE);
1116 		break;
1117 
1118 	case PRIO_DARWIN_RUNAWAY_MITIGATION_ON:
1119 		/*
1120 		 * RunningBoard-managed processes are not mitigatable - they should be
1121 		 * managed through RunningBoard-level interfaces instead.
1122 		 * Set the boot arg allow_managed_mitigation=1 to allow this.
1123 		 */
1124 		if (memorystatus_get_proc_is_managed(targetp) && !allow_managed_mitigation) {
1125 			printf("%s[%d] blocked from disabling runaway mitigation on RunningBoard managed process %s[%d]\n",
1126 			    proc_best_name(current_proc()), proc_selfpid(),
1127 			    proc_best_name(targetp), proc_getpid(targetp));
1128 
1129 			error = ENOTSUP;
1130 			goto out;
1131 		}
1132 
1133 		proc_set_task_policy(proc_task(targetp), TASK_POLICY_ATTRIBUTE,
1134 		    TASK_POLICY_RUNAWAY_MITIGATION, TASK_POLICY_ENABLE);
1135 
1136 		printf("%s[%d] enabling runaway mitigation on %s[%d]\n",
1137 		    proc_best_name(current_proc()), proc_selfpid(),
1138 		    proc_best_name(targetp), proc_getpid(targetp));
1139 		break;
1140 
1141 	default:
1142 		error = EINVAL;
1143 		goto out;
1144 	}
1145 
1146 out:
1147 	kauth_cred_unref(&target_cred);
1148 	return error;
1149 }
1150 
1151 static int
proc_get_runaway_mitigation(proc_t targetp,int * priority)1152 proc_get_runaway_mitigation(proc_t targetp, int *priority)
1153 {
1154 	int error = 0;
1155 
1156 	kauth_cred_t ucred, target_cred;
1157 
1158 	ucred = kauth_cred_get();
1159 	target_cred = kauth_cred_proc_ref(targetp);
1160 
1161 	boolean_t entitled = FALSE;
1162 	entitled = IOCurrentTaskHasEntitlement(RUNAWAY_MITIGATION_ENTITLEMENT);
1163 
1164 	/* Root is allowed to get without entitlement */
1165 	if (!kauth_cred_issuser(ucred) && !entitled) {
1166 		error = EPERM;
1167 		goto out;
1168 	}
1169 
1170 	/* Even with entitlement, non-root is only alllowed to see same-user */
1171 	if (!kauth_cred_issuser(ucred) &&
1172 	    kauth_cred_getuid(ucred) != kauth_cred_getuid(target_cred)) {
1173 		error = EPERM;
1174 		goto out;
1175 	}
1176 
1177 	if (proc_get_task_policy(proc_task(targetp), TASK_POLICY_ATTRIBUTE, TASK_POLICY_RUNAWAY_MITIGATION)) {
1178 		*priority = PRIO_DARWIN_RUNAWAY_MITIGATION_ON;
1179 	} else {
1180 		*priority = PRIO_DARWIN_RUNAWAY_MITIGATION_OFF;
1181 	}
1182 
1183 out:
1184 	kauth_cred_unref(&target_cred);
1185 	return error;
1186 }
1187 
1188 
1189 static int
get_background_proc(struct proc * curp,struct proc * targetp,int * priority)1190 get_background_proc(struct proc *curp, struct proc *targetp, int *priority)
1191 {
1192 	int external = 0;
1193 	int error = 0;
1194 	kauth_cred_t ucred, target_cred;
1195 
1196 	ucred = kauth_cred_get();
1197 	target_cred = kauth_cred_proc_ref(targetp);
1198 
1199 	if (!kauth_cred_issuser(ucred) && kauth_cred_getruid(ucred) &&
1200 	    kauth_cred_getuid(ucred) != kauth_cred_getuid(target_cred) &&
1201 	    kauth_cred_getruid(ucred) != kauth_cred_getuid(target_cred)) {
1202 		error = EPERM;
1203 		goto out;
1204 	}
1205 
1206 	external = (curp == targetp) ? TASK_POLICY_INTERNAL : TASK_POLICY_EXTERNAL;
1207 
1208 	*priority = proc_get_task_policy(current_task(), external, TASK_POLICY_DARWIN_BG);
1209 
1210 out:
1211 	kauth_cred_unref(&target_cred);
1212 	return error;
1213 }
1214 
1215 static int
do_background_proc(struct proc * curp,struct proc * targetp,int priority)1216 do_background_proc(struct proc *curp, struct proc *targetp, int priority)
1217 {
1218 #if !CONFIG_MACF
1219 #pragma unused(curp)
1220 #endif
1221 	int error = 0;
1222 	kauth_cred_t ucred;
1223 	kauth_cred_t target_cred;
1224 	int external;
1225 	int enable;
1226 
1227 	ucred = kauth_cred_get();
1228 	target_cred = kauth_cred_proc_ref(targetp);
1229 
1230 	if (!kauth_cred_issuser(ucred) && kauth_cred_getruid(ucred) &&
1231 	    kauth_cred_getuid(ucred) != kauth_cred_getuid(target_cred) &&
1232 	    kauth_cred_getruid(ucred) != kauth_cred_getuid(target_cred)) {
1233 		error = EPERM;
1234 		goto out;
1235 	}
1236 
1237 #if CONFIG_MACF
1238 	error = mac_proc_check_sched(curp, targetp);
1239 	if (error) {
1240 		goto out;
1241 	}
1242 #endif
1243 
1244 	external = (curp == targetp) ? TASK_POLICY_INTERNAL : TASK_POLICY_EXTERNAL;
1245 
1246 	switch (priority) {
1247 	case PRIO_DARWIN_BG:
1248 		enable = TASK_POLICY_ENABLE;
1249 		break;
1250 	case PRIO_DARWIN_NONUI:
1251 		/* ignored for compatibility */
1252 		goto out;
1253 	default:
1254 		/* TODO: EINVAL if priority != 0 */
1255 		enable = TASK_POLICY_DISABLE;
1256 		break;
1257 	}
1258 
1259 	proc_set_task_policy(proc_task(targetp), external, TASK_POLICY_DARWIN_BG, enable);
1260 
1261 out:
1262 	kauth_cred_unref(&target_cred);
1263 	return error;
1264 }
1265 
1266 static void
do_background_socket(struct proc * p,thread_t thread)1267 do_background_socket(struct proc *p, thread_t thread)
1268 {
1269 #if SOCKETS
1270 	struct fileproc *fp;
1271 	int              background = false;
1272 #if NECP
1273 	int              update_necp = false;
1274 #endif /* NECP */
1275 
1276 	if (thread != THREAD_NULL &&
1277 	    get_threadtask(thread) != proc_task(p)) {
1278 		return;
1279 	}
1280 
1281 	proc_fdlock(p);
1282 
1283 	if (thread != THREAD_NULL) {
1284 		background = proc_get_effective_thread_policy(thread, TASK_POLICY_ALL_SOCKETS_BG);
1285 	} else {
1286 		background = proc_get_effective_task_policy(proc_task(p), TASK_POLICY_ALL_SOCKETS_BG);
1287 	}
1288 
1289 	if (background) {
1290 		/*
1291 		 * For PRIO_DARWIN_PROCESS (thread is NULL), simply mark
1292 		 * the sockets with the background flag.  There's nothing
1293 		 * to do here for the PRIO_DARWIN_THREAD case.
1294 		 */
1295 		if (thread == THREAD_NULL) {
1296 			fdt_foreach(fp, p) {
1297 				if (FILEGLOB_DTYPE(fp->fp_glob) == DTYPE_SOCKET) {
1298 					struct socket *sockp = (struct socket *)fp_get_data(fp);
1299 					socket_set_traffic_mgt_flags(sockp, TRAFFIC_MGT_SO_BACKGROUND);
1300 					sockp->so_background_thread = NULL;
1301 				}
1302 #if NECP
1303 				else if (FILEGLOB_DTYPE(fp->fp_glob) == DTYPE_NETPOLICY) {
1304 					if (necp_set_client_as_background(p, fp, background)) {
1305 						update_necp = true;
1306 					}
1307 				}
1308 #endif /* NECP */
1309 			}
1310 		}
1311 	} else {
1312 		/* disable networking IO throttle.
1313 		 * NOTE - It is a known limitation of the current design that we
1314 		 * could potentially clear TRAFFIC_MGT_SO_BACKGROUND bit for
1315 		 * sockets created by other threads within this process.
1316 		 */
1317 		fdt_foreach(fp, p) {
1318 			struct socket *sockp;
1319 
1320 			if (FILEGLOB_DTYPE(fp->fp_glob) == DTYPE_SOCKET) {
1321 				sockp = (struct socket *)fp_get_data(fp);
1322 				/* skip if only clearing this thread's sockets */
1323 				if ((thread) && (sockp->so_background_thread != thread)) {
1324 					continue;
1325 				}
1326 				socket_clear_traffic_mgt_flags(sockp, TRAFFIC_MGT_SO_BACKGROUND);
1327 				sockp->so_background_thread = NULL;
1328 			}
1329 #if NECP
1330 			else if (FILEGLOB_DTYPE(fp->fp_glob) == DTYPE_NETPOLICY) {
1331 				if (necp_set_client_as_background(p, fp, background)) {
1332 					update_necp = true;
1333 				}
1334 			}
1335 #endif /* NECP */
1336 		}
1337 	}
1338 
1339 	proc_fdunlock(p);
1340 
1341 #if NECP
1342 	if (update_necp) {
1343 		necp_update_all_clients();
1344 	}
1345 #endif /* NECP */
1346 #else
1347 #pragma unused(p, thread)
1348 #endif
1349 }
1350 
1351 
1352 /*
1353  * do_background_thread
1354  *
1355  * Requires: thread reference
1356  *
1357  * Returns:     0                       Success
1358  *              EPERM                   Tried to background while in vfork
1359  * XXX - todo - does this need a MACF hook?
1360  */
1361 static int
do_background_thread(thread_t thread,int priority)1362 do_background_thread(thread_t thread, int priority)
1363 {
1364 	int enable, external;
1365 	int rv = 0;
1366 
1367 	/* Backgrounding is unsupported for workq threads */
1368 	if (thread_is_static_param(thread)) {
1369 		return EPERM;
1370 	}
1371 
1372 	/* Not allowed to combine QoS and DARWIN_BG, doing so strips the QoS */
1373 	if (thread_has_qos_policy(thread)) {
1374 		thread_remove_qos_policy(thread);
1375 		rv = EIDRM;
1376 	}
1377 
1378 	/* TODO: Fail if someone passes something besides 0 or PRIO_DARWIN_BG */
1379 	enable   = (priority == PRIO_DARWIN_BG) ? TASK_POLICY_ENABLE   : TASK_POLICY_DISABLE;
1380 	external = (current_thread() == thread) ? TASK_POLICY_INTERNAL : TASK_POLICY_EXTERNAL;
1381 
1382 	proc_set_thread_policy(thread, external, TASK_POLICY_DARWIN_BG, enable);
1383 
1384 	return rv;
1385 }
1386 
1387 
1388 /*
1389  * Returns:	0			Success
1390  *	copyin:EFAULT
1391  *	dosetrlimit:
1392  */
1393 /* ARGSUSED */
1394 int
setrlimit(struct proc * p,struct setrlimit_args * uap,__unused int32_t * retval)1395 setrlimit(struct proc *p, struct setrlimit_args *uap, __unused int32_t *retval)
1396 {
1397 	struct rlimit alim;
1398 	int error;
1399 
1400 	if ((error = copyin(uap->rlp, (caddr_t)&alim,
1401 	    sizeof(struct rlimit)))) {
1402 		return error;
1403 	}
1404 
1405 	return dosetrlimit(p, uap->which, &alim);
1406 }
1407 
1408 /*
1409  * Returns:	0			Success
1410  *		EINVAL
1411  *	suser:EPERM
1412  *
1413  * Notes:	EINVAL is returned both for invalid arguments, and in the
1414  *		case that the current usage (e.g. RLIMIT_STACK) is already
1415  *		in excess of the requested limit.
1416  */
1417 static int
dosetrlimit(struct proc * p,u_int which,struct rlimit * newrlim)1418 dosetrlimit(struct proc *p, u_int which, struct rlimit *newrlim)
1419 {
1420 	struct rlimit        rlim, stack_rlim = {.rlim_cur = 0, .rlim_max = 0};
1421 	int                  error;
1422 	kern_return_t        kr;
1423 
1424 	/* Mask out POSIX flag, saved above */
1425 	which &= ~_RLIMIT_POSIX_FLAG;
1426 
1427 	/* Unknown resource */
1428 	if (which >= RLIM_NLIMITS) {
1429 		return EINVAL;
1430 	}
1431 
1432 	proc_lock(p);
1433 
1434 	/* Only one thread is able to change the current process's rlimit values */
1435 	proc_limitblock(p);
1436 
1437 	/*
1438 	 * Take a snapshot of the current rlimit values and read this throughout
1439 	 * this routine. This minimizes the critical sections and allow other
1440 	 * processes in the system to access the plimit while we are in the
1441 	 * middle of this setrlimit call.
1442 	 */
1443 	rlim = smr_serialized_load(&p->p_limit)->pl_rlimit[which];
1444 
1445 	proc_unlock(p);
1446 
1447 	error = 0;
1448 	/* Sanity check: new soft limit cannot exceed new hard limit */
1449 	if (newrlim->rlim_cur > newrlim->rlim_max) {
1450 		error = EINVAL;
1451 	}
1452 	/*
1453 	 * Sanity check: only super-user may raise the hard limit.
1454 	 * newrlim->rlim_cur > rlim.rlim_max implies that the call
1455 	 * is increasing the hard limit as well.
1456 	 */
1457 	else if (newrlim->rlim_cur > rlim.rlim_max || newrlim->rlim_max > rlim.rlim_max) {
1458 		/* suser() returns 0 if the calling thread is super user. */
1459 		error = suser(kauth_cred_get(), &p->p_acflag);
1460 	}
1461 
1462 	if (error) {
1463 		/* Invalid setrlimit request: EINVAL or EPERM */
1464 		goto out;
1465 	}
1466 
1467 	/* We have the reader lock of the process's plimit so it's safe to read the rlimit values */
1468 	switch (which) {
1469 	case RLIMIT_CPU:
1470 		if (newrlim->rlim_cur == RLIM_INFINITY) {
1471 			task_vtimer_clear(proc_task(p), TASK_VTIMER_RLIM);
1472 			timerclear(&p->p_rlim_cpu);
1473 		} else {
1474 			task_absolutetime_info_data_t   tinfo;
1475 			mach_msg_type_number_t          count;
1476 			struct timeval                  ttv, tv;
1477 			clock_sec_t                     tv_sec;
1478 			clock_usec_t                    tv_usec;
1479 
1480 			count = TASK_ABSOLUTETIME_INFO_COUNT;
1481 			task_info(proc_task(p), TASK_ABSOLUTETIME_INFO, (task_info_t)&tinfo, &count);
1482 			absolutetime_to_microtime(tinfo.total_user + tinfo.total_system, &tv_sec, &tv_usec);
1483 			ttv.tv_sec = tv_sec;
1484 			ttv.tv_usec = tv_usec;
1485 
1486 			tv.tv_sec = (newrlim->rlim_cur > __INT_MAX__ ? __INT_MAX__ : (__darwin_time_t)newrlim->rlim_cur);
1487 			tv.tv_usec = 0;
1488 			timersub(&tv, &ttv, &p->p_rlim_cpu);
1489 
1490 			timerclear(&tv);
1491 			if (timercmp(&p->p_rlim_cpu, &tv, >)) {
1492 				task_vtimer_set(proc_task(p), TASK_VTIMER_RLIM);
1493 			} else {
1494 				task_vtimer_clear(proc_task(p), TASK_VTIMER_RLIM);
1495 
1496 				timerclear(&p->p_rlim_cpu);
1497 
1498 				psignal(p, SIGXCPU);
1499 			}
1500 		}
1501 		break;
1502 
1503 	case RLIMIT_DATA:
1504 #if 00
1505 		if (newrlim->rlim_cur > maxdmap) {
1506 			newrlim->rlim_cur = maxdmap;
1507 		}
1508 		if (newrlim->rlim_max > maxdmap) {
1509 			newrlim->rlim_max = maxdmap;
1510 		}
1511 #endif
1512 
1513 		/* Over to Mach VM to validate the new data limit */
1514 		if (vm_map_set_data_limit(current_map(), newrlim->rlim_cur) != KERN_SUCCESS) {
1515 			/* The limit specified cannot be lowered because current usage is already higher than the limit. */
1516 			error =  EINVAL;
1517 			goto out;
1518 		}
1519 		break;
1520 
1521 	case RLIMIT_STACK:
1522 		if (p->p_lflag & P_LCUSTOM_STACK) {
1523 			/* Process has a custom stack set - rlimit cannot be used to change it */
1524 			error = EINVAL;
1525 			goto out;
1526 		}
1527 
1528 		/*
1529 		 * Note: the real stack size limit is enforced by maxsmap, not a process's RLIMIT_STACK.
1530 		 *
1531 		 * The kernel uses maxsmap to control the actual stack size limit. While we allow
1532 		 * processes to set RLIMIT_STACK to RLIM_INFINITY (UNIX 03), accessing memory
1533 		 * beyond the maxsmap will still trigger an exception.
1534 		 *
1535 		 * stack_rlim is used to store the user-defined RLIMIT_STACK values while we adjust
1536 		 * the stack size using kernel limit (i.e. maxsmap).
1537 		 */
1538 		if (newrlim->rlim_cur > maxsmap ||
1539 		    newrlim->rlim_max > maxsmap) {
1540 			if (newrlim->rlim_cur > maxsmap) {
1541 				stack_rlim.rlim_cur = newrlim->rlim_cur;
1542 				newrlim->rlim_cur = maxsmap;
1543 			}
1544 			if (newrlim->rlim_max > maxsmap) {
1545 				stack_rlim.rlim_max = newrlim->rlim_max;
1546 				newrlim->rlim_max = maxsmap;
1547 			}
1548 		}
1549 
1550 		/*
1551 		 * rlim.rlim_cur/rlim_max could be arbitrarily large due to previous calls to setrlimit().
1552 		 * Use the actual size for stack region adjustment.
1553 		 */
1554 		if (rlim.rlim_cur > maxsmap) {
1555 			rlim.rlim_cur = maxsmap;
1556 		}
1557 		if (rlim.rlim_max > maxsmap) {
1558 			rlim.rlim_max = maxsmap;
1559 		}
1560 
1561 		/*
1562 		 * Stack is allocated to the max at exec time with only
1563 		 * "rlim_cur" bytes accessible.  If stack limit is going
1564 		 * up make more accessible, if going down make inaccessible.
1565 		 */
1566 		if (newrlim->rlim_cur > rlim.rlim_cur) {
1567 			mach_vm_offset_t addr;
1568 			mach_vm_size_t size;
1569 
1570 			/* grow stack */
1571 			size = newrlim->rlim_cur;
1572 			if (round_page_overflow(size, &size)) {
1573 				error = EINVAL;
1574 				goto out;
1575 			}
1576 			size -= round_page_64(rlim.rlim_cur);
1577 
1578 			addr = (mach_vm_offset_t)(p->user_stack - round_page_64(newrlim->rlim_cur));
1579 			kr = mach_vm_protect(current_map(), addr, size, FALSE, VM_PROT_DEFAULT);
1580 			if (kr != KERN_SUCCESS) {
1581 				error = EINVAL;
1582 				goto out;
1583 			}
1584 		} else if (newrlim->rlim_cur < rlim.rlim_cur) {
1585 			mach_vm_offset_t addr;
1586 			mach_vm_size_t size;
1587 			uint64_t cur_sp;
1588 
1589 			/* shrink stack */
1590 
1591 			/*
1592 			 * First check if new stack limit would agree
1593 			 * with current stack usage.
1594 			 * Get the current thread's stack pointer...
1595 			 */
1596 			cur_sp = thread_adjuserstack(current_thread(), 0);
1597 			if (cur_sp <= p->user_stack &&
1598 			    cur_sp > (p->user_stack - round_page_64(rlim.rlim_cur))) {
1599 				/* stack pointer is in main stack */
1600 				if (cur_sp <= (p->user_stack - round_page_64(newrlim->rlim_cur))) {
1601 					/*
1602 					 * New limit would cause current usage to be invalid:
1603 					 * reject new limit.
1604 					 */
1605 					error =  EINVAL;
1606 					goto out;
1607 				}
1608 			} else {
1609 				/* not on the main stack: reject */
1610 				error =  EINVAL;
1611 				goto out;
1612 			}
1613 
1614 			size = round_page_64(rlim.rlim_cur);
1615 			size -= round_page_64(rlim.rlim_cur);
1616 
1617 			addr = (mach_vm_offset_t)(p->user_stack - round_page_64(rlim.rlim_cur));
1618 
1619 			kr = mach_vm_protect(current_map(), addr, size, FALSE, VM_PROT_NONE);
1620 			if (kr != KERN_SUCCESS) {
1621 				error =  EINVAL;
1622 				goto out;
1623 			}
1624 		} else {
1625 			/* no change ... */
1626 		}
1627 
1628 		/*
1629 		 * We've adjusted the process's stack region. If the user-defined limit is greater
1630 		 * than maxsmap, we need to reflect this change in rlimit interface.
1631 		 */
1632 		if (stack_rlim.rlim_cur != 0) {
1633 			newrlim->rlim_cur = stack_rlim.rlim_cur;
1634 		}
1635 		if (stack_rlim.rlim_max != 0) {
1636 			newrlim->rlim_max = stack_rlim.rlim_max;
1637 		}
1638 		break;
1639 
1640 	case RLIMIT_NOFILE:
1641 		/*
1642 		 * Nothing to be done here as we already performed the sanity checks before entering the switch code block.
1643 		 * The real NOFILE limits enforced by the kernel is capped at MIN(RLIMIT_NOFILE, maxfilesperproc)
1644 		 */
1645 		break;
1646 
1647 	case RLIMIT_AS:
1648 		/* Over to Mach VM to validate the new address space limit */
1649 		if (vm_map_set_size_limit(current_map(), newrlim->rlim_cur) != KERN_SUCCESS) {
1650 			/* The limit specified cannot be lowered because current usage is already higher than the limit. */
1651 			error =  EINVAL;
1652 			goto out;
1653 		}
1654 		break;
1655 
1656 	case RLIMIT_NPROC:
1657 		/*
1658 		 * Only root can set to the maxproc limits, as it is
1659 		 * systemwide resource; all others are limited to
1660 		 * maxprocperuid (presumably less than maxproc).
1661 		 */
1662 		if (kauth_cred_issuser(kauth_cred_get())) {
1663 			if (newrlim->rlim_cur > (rlim_t)maxproc) {
1664 				newrlim->rlim_cur = maxproc;
1665 			}
1666 			if (newrlim->rlim_max > (rlim_t)maxproc) {
1667 				newrlim->rlim_max = maxproc;
1668 			}
1669 		} else {
1670 			if (newrlim->rlim_cur > (rlim_t)maxprocperuid) {
1671 				newrlim->rlim_cur = maxprocperuid;
1672 			}
1673 			if (newrlim->rlim_max > (rlim_t)maxprocperuid) {
1674 				newrlim->rlim_max = maxprocperuid;
1675 			}
1676 		}
1677 		break;
1678 
1679 	case RLIMIT_MEMLOCK:
1680 		/*
1681 		 * Tell the Mach VM layer about the new limit value.
1682 		 */
1683 		newrlim->rlim_cur = (vm_size_t)newrlim->rlim_cur;
1684 		vm_map_set_user_wire_limit(current_map(), (vm_size_t)newrlim->rlim_cur);
1685 		break;
1686 	} /* switch... */
1687 
1688 	/* Everything checks out and we are now ready to update the rlimit */
1689 	error = 0;
1690 
1691 out:
1692 
1693 	if (error == 0) {
1694 		/*
1695 		 * COW the current plimit if it's shared, otherwise update it in place.
1696 		 * Finally unblock other threads wishing to change plimit.
1697 		 */
1698 		proc_limitupdate(p, true, ^(struct plimit *plim) {
1699 			plim->pl_rlimit[which] = *newrlim;
1700 		});
1701 	} else {
1702 		/*
1703 		 * This setrlimit has failed, just leave the plimit as is and unblock other
1704 		 * threads wishing to change plimit.
1705 		 */
1706 		proc_lock(p);
1707 		proc_limitunblock(p);
1708 		proc_unlock(p);
1709 	}
1710 
1711 	return error;
1712 }
1713 
1714 /* ARGSUSED */
1715 int
getrlimit(struct proc * p,struct getrlimit_args * uap,__unused int32_t * retval)1716 getrlimit(struct proc *p, struct getrlimit_args *uap, __unused int32_t *retval)
1717 {
1718 	struct rlimit lim = {};
1719 
1720 	/*
1721 	 * Take out flag now in case we need to use it to trigger variant
1722 	 * behaviour later.
1723 	 */
1724 	uap->which &= ~_RLIMIT_POSIX_FLAG;
1725 
1726 	if (uap->which >= RLIM_NLIMITS) {
1727 		return EINVAL;
1728 	}
1729 	lim = proc_limitget(p, uap->which);
1730 	return copyout((caddr_t)&lim, uap->rlp, sizeof(struct rlimit));
1731 }
1732 
1733 static struct timeval
_absolutetime_to_timeval(uint64_t abstime)1734 _absolutetime_to_timeval(uint64_t abstime)
1735 {
1736 	clock_sec_t sec;
1737 	clock_usec_t usec;
1738 	absolutetime_to_microtime(abstime, &sec, &usec);
1739 	return (struct timeval){
1740 		       .tv_sec = sec,
1741 		       .tv_usec = usec,
1742 	};
1743 }
1744 
1745 /*
1746  * Transform the running time and tick information in proc p into user,
1747  * system, and interrupt time usage.
1748  */
1749 void
calcru(struct proc * p,struct timeval * up,struct timeval * sp,struct timeval * ip)1750 calcru(struct proc *p, struct timeval *up, struct timeval *sp, struct timeval *ip)
1751 {
1752 	task_t task;
1753 
1754 	if (ip != NULL) {
1755 		timerclear(ip);
1756 	}
1757 
1758 	task = proc_task(p);
1759 	if (task) {
1760 		mach_task_basic_info_data_t tinfo;
1761 		mach_msg_type_number_t task_info_count;
1762 		mach_msg_type_number_t task_events_count;
1763 		task_events_info_data_t teventsinfo;
1764 		struct recount_times_mach times;
1765 
1766 		task_info_count = MACH_TASK_BASIC_INFO_COUNT;
1767 		task_info(task, MACH_TASK_BASIC_INFO,
1768 		    (task_info_t)&tinfo, &task_info_count);
1769 		task_events_count = TASK_EVENTS_INFO_COUNT;
1770 		task_info(task, TASK_EVENTS_INFO,
1771 		    (task_info_t)&teventsinfo, &task_events_count);
1772 
1773 		times = recount_task_times(task);
1774 		*up = _absolutetime_to_timeval(times.rtm_user);
1775 		*sp = _absolutetime_to_timeval(times.rtm_system);
1776 
1777 		/*
1778 		 * No lock is held here, but it's only a consistency issue for non-
1779 		 * getrusage(2) callers of this function.
1780 		 */
1781 		p->p_stats->p_ru.ru_minflt = teventsinfo.faults -
1782 		    teventsinfo.pageins;
1783 		p->p_stats->p_ru.ru_majflt = teventsinfo.pageins;
1784 		p->p_stats->p_ru.ru_nivcsw = teventsinfo.csw -
1785 		    p->p_stats->p_ru.ru_nvcsw;
1786 		if (p->p_stats->p_ru.ru_nivcsw < 0) {
1787 			p->p_stats->p_ru.ru_nivcsw = 0;
1788 		}
1789 
1790 		p->p_stats->p_ru.ru_maxrss = (long)tinfo.resident_size_max;
1791 	} else {
1792 		timerclear(up);
1793 		timerclear(sp);
1794 	}
1795 }
1796 
1797 __private_extern__ void munge_user64_rusage(struct rusage *a_rusage_p, struct user64_rusage *a_user_rusage_p);
1798 __private_extern__ void munge_user32_rusage(struct rusage *a_rusage_p, struct user32_rusage *a_user_rusage_p);
1799 
1800 /* ARGSUSED */
1801 int
getrusage(struct proc * p,struct getrusage_args * uap,__unused int32_t * retval)1802 getrusage(struct proc *p, struct getrusage_args *uap, __unused int32_t *retval)
1803 {
1804 	struct rusage *rup, rubuf;
1805 	struct user64_rusage rubuf64 = {};
1806 	struct user32_rusage rubuf32 = {};
1807 	size_t retsize = sizeof(rubuf);                 /* default: 32 bits */
1808 	caddr_t retbuf = (caddr_t)&rubuf;               /* default: 32 bits */
1809 	struct timeval utime;
1810 	struct timeval stime;
1811 
1812 	switch (uap->who) {
1813 	case RUSAGE_SELF:
1814 		calcru(p, &utime, &stime, NULL);
1815 		proc_lock(p);
1816 		rup = &p->p_stats->p_ru;
1817 		rup->ru_utime = utime;
1818 		rup->ru_stime = stime;
1819 
1820 		rubuf = *rup;
1821 		proc_unlock(p);
1822 
1823 		break;
1824 
1825 	case RUSAGE_CHILDREN:
1826 		proc_lock(p);
1827 		rup = &p->p_stats->p_cru;
1828 		rubuf = *rup;
1829 		proc_unlock(p);
1830 		break;
1831 
1832 	default:
1833 		return EINVAL;
1834 	}
1835 	if (IS_64BIT_PROCESS(p)) {
1836 		retsize = sizeof(rubuf64);
1837 		retbuf = (caddr_t)&rubuf64;
1838 		munge_user64_rusage(&rubuf, &rubuf64);
1839 	} else {
1840 		retsize = sizeof(rubuf32);
1841 		retbuf = (caddr_t)&rubuf32;
1842 		munge_user32_rusage(&rubuf, &rubuf32);
1843 	}
1844 
1845 	return copyout(retbuf, uap->rusage, retsize);
1846 }
1847 
1848 void
ruadd(struct rusage * ru,struct rusage * ru2)1849 ruadd(struct rusage *ru, struct rusage *ru2)
1850 {
1851 	long *ip, *ip2;
1852 	long i;
1853 
1854 	timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
1855 	timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
1856 	if (ru->ru_maxrss < ru2->ru_maxrss) {
1857 		ru->ru_maxrss = ru2->ru_maxrss;
1858 	}
1859 	ip = &ru->ru_first; ip2 = &ru2->ru_first;
1860 	for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--) {
1861 		*ip++ += *ip2++;
1862 	}
1863 }
1864 
1865 /*
1866  * Add the rusage stats of child in parent.
1867  *
1868  * It adds rusage statistics of child process and statistics of all its
1869  * children to its parent.
1870  *
1871  * Note: proc lock of parent should be held while calling this function.
1872  */
1873 void
update_rusage_info_child(struct rusage_info_child * ri,rusage_info_current * ri_current)1874 update_rusage_info_child(struct rusage_info_child *ri, rusage_info_current *ri_current)
1875 {
1876 	ri->ri_child_user_time += (ri_current->ri_user_time +
1877 	    ri_current->ri_child_user_time);
1878 	ri->ri_child_system_time += (ri_current->ri_system_time +
1879 	    ri_current->ri_child_system_time);
1880 	ri->ri_child_pkg_idle_wkups += (ri_current->ri_pkg_idle_wkups +
1881 	    ri_current->ri_child_pkg_idle_wkups);
1882 	ri->ri_child_interrupt_wkups += (ri_current->ri_interrupt_wkups +
1883 	    ri_current->ri_child_interrupt_wkups);
1884 	ri->ri_child_pageins += (ri_current->ri_pageins +
1885 	    ri_current->ri_child_pageins);
1886 	ri->ri_child_elapsed_abstime += ((ri_current->ri_proc_exit_abstime -
1887 	    ri_current->ri_proc_start_abstime) + ri_current->ri_child_elapsed_abstime);
1888 }
1889 
1890 static void
proc_limit_free(smr_node_t node)1891 proc_limit_free(smr_node_t node)
1892 {
1893 	struct plimit *plimit = __container_of(node, struct plimit, pl_node);
1894 
1895 	zfree(plimit_zone, plimit);
1896 }
1897 
1898 static void
proc_limit_release(struct plimit * plimit)1899 proc_limit_release(struct plimit *plimit)
1900 {
1901 	if (os_ref_release(&plimit->pl_refcnt) == 0) {
1902 		smr_proc_task_call(&plimit->pl_node, sizeof(*plimit), proc_limit_free);
1903 	}
1904 }
1905 
1906 /*
1907  * Reading soft limit from specified resource.
1908  */
1909 rlim_t
proc_limitgetcur(proc_t p,int which)1910 proc_limitgetcur(proc_t p, int which)
1911 {
1912 	rlim_t rlim_cur;
1913 
1914 	assert(p);
1915 	assert(which < RLIM_NLIMITS);
1916 
1917 	smr_proc_task_enter();
1918 	rlim_cur = smr_entered_load(&p->p_limit)->pl_rlimit[which].rlim_cur;
1919 	smr_proc_task_leave();
1920 
1921 	return rlim_cur;
1922 }
1923 
1924 /*
1925  * Handle commonly asked limit that needs to be clamped with maxfilesperproc.
1926  */
1927 int
proc_limitgetcur_nofile(struct proc * p)1928 proc_limitgetcur_nofile(struct proc *p)
1929 {
1930 	rlim_t lim = proc_limitgetcur(p, RLIMIT_NOFILE);
1931 
1932 	return (int)MIN(lim, maxfilesperproc);
1933 }
1934 
1935 /*
1936  * Writing soft limit to specified resource. This is an internal function
1937  * used only by proc_exit to update RLIMIT_FSIZE in
1938  * place without invoking setrlimit.
1939  */
1940 void
proc_limitsetcur_fsize(proc_t p,rlim_t value)1941 proc_limitsetcur_fsize(proc_t p, rlim_t value)
1942 {
1943 	proc_limitupdate(p, false, ^(struct plimit *plimit) {
1944 		plimit->pl_rlimit[RLIMIT_FSIZE].rlim_cur = value;
1945 	});
1946 }
1947 
1948 struct rlimit
proc_limitget(proc_t p,int which)1949 proc_limitget(proc_t p, int which)
1950 {
1951 	struct rlimit lim;
1952 
1953 	assert(which < RLIM_NLIMITS);
1954 
1955 	smr_proc_task_enter();
1956 	lim = smr_entered_load(&p->p_limit)->pl_rlimit[which];
1957 	smr_proc_task_leave();
1958 
1959 	return lim;
1960 }
1961 
1962 void
proc_limitfork(proc_t parent,proc_t child)1963 proc_limitfork(proc_t parent, proc_t child)
1964 {
1965 	struct plimit *plim;
1966 
1967 	proc_lock(parent);
1968 	plim = smr_serialized_load(&parent->p_limit);
1969 	os_ref_retain(&plim->pl_refcnt);
1970 	proc_unlock(parent);
1971 
1972 	smr_init_store(&child->p_limit, plim);
1973 }
1974 
1975 void
proc_limitdrop(proc_t p)1976 proc_limitdrop(proc_t p)
1977 {
1978 	struct plimit *plimit = NULL;
1979 
1980 	proc_lock(p);
1981 	plimit = smr_serialized_load(&p->p_limit);
1982 	smr_clear_store(&p->p_limit);
1983 	proc_unlock(p);
1984 
1985 	proc_limit_release(plimit);
1986 }
1987 
1988 /*
1989  * proc_limitblock/unblock are used to serialize access to plimit
1990  * from concurrent threads within the same process.
1991  * Callers must be holding the proc lock to enter, return with
1992  * the proc lock locked
1993  */
1994 static void
proc_limitblock(proc_t p)1995 proc_limitblock(proc_t p)
1996 {
1997 	lck_mtx_assert(&p->p_mlock, LCK_MTX_ASSERT_OWNED);
1998 
1999 	while (p->p_lflag & P_LLIMCHANGE) {
2000 		p->p_lflag |= P_LLIMWAIT;
2001 		msleep(&p->p_limit, &p->p_mlock, 0, "proc_limitblock", NULL);
2002 	}
2003 	p->p_lflag |= P_LLIMCHANGE;
2004 }
2005 
2006 /*
2007  * Callers must be holding the proc lock to enter, return with
2008  * the proc lock locked
2009  */
2010 static void
proc_limitunblock(proc_t p)2011 proc_limitunblock(proc_t p)
2012 {
2013 	lck_mtx_assert(&p->p_mlock, LCK_MTX_ASSERT_OWNED);
2014 
2015 	p->p_lflag &= ~P_LLIMCHANGE;
2016 	if (p->p_lflag & P_LLIMWAIT) {
2017 		p->p_lflag &= ~P_LLIMWAIT;
2018 		wakeup(&p->p_limit);
2019 	}
2020 }
2021 
2022 /*
2023  * Perform an rlimit update (as defined by the arbitrary `update` function).
2024  *
2025  * Because plimits are accessed without holding any locks,
2026  * with only a hazard reference, the struct plimit is always
2027  * copied, updated, and replaced, to implement a const value type.
2028  */
2029 static void
2030 proc_limitupdate(proc_t p, bool unblock, void (^update)(struct plimit *))
2031 {
2032 	struct plimit  *cur_plim;
2033 	struct plimit  *copy_plim;
2034 
2035 	copy_plim = zalloc_flags(plimit_zone, Z_WAITOK | Z_ZERO | Z_NOFAIL);
2036 
2037 	proc_lock(p);
2038 
2039 	cur_plim = smr_serialized_load(&p->p_limit);
2040 
2041 	os_ref_init_count(&copy_plim->pl_refcnt, &rlimit_refgrp, 1);
2042 	bcopy(cur_plim->pl_rlimit, copy_plim->pl_rlimit,
2043 	    sizeof(struct rlimit) * RLIM_NLIMITS);
2044 
2045 	update(copy_plim);
2046 
2047 	smr_serialized_store(&p->p_limit, copy_plim);
2048 
2049 	if (unblock) {
2050 		proc_limitunblock(p);
2051 	}
2052 	proc_unlock(p);
2053 
2054 	proc_limit_release(cur_plim);
2055 }
2056 
2057 static int
2058 iopolicysys_disk(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *iop_param);
2059 static int
2060 iopolicysys_vfs_hfs_case_sensitivity(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *iop_param);
2061 static int
2062 iopolicysys_vfs_atime_updates(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *iop_param);
2063 static int
2064 iopolicysys_vfs_statfs_no_data_volume(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *iop_param);
2065 static int
2066 iopolicysys_vfs_trigger_resolve(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *iop_param);
2067 static int
2068 iopolicysys_vfs_ignore_content_protection(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *iop_param);
2069 static int
2070 iopolicysys_vfs_ignore_node_permissions(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *ipo_param);
2071 static int
2072 iopolicysys_vfs_skip_mtime_update(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *iop_param);
2073 static int
2074 iopolicysys_vfs_allow_lowspace_writes(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *iop_param);
2075 static int
2076 iopolicysys_vfs_disallow_rw_for_o_evtonly(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *iop_param);
2077 static int iopolicysys_vfs_altlink(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *iop_param);
2078 static int iopolicysys_vfs_nocache_write_fs_blksize(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *iop_param);
2079 static int
2080 iopolicysys_vfs_support_long_paths(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *iop_param);
2081 static int
2082 iopolicysys_vfs_entitled_reserve_access(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *iop_param);
2083 
2084 /*
2085  * iopolicysys
2086  *
2087  * Description:	System call MUX for use in manipulating I/O policy attributes of the current process or thread
2088  *
2089  * Parameters:	cmd				Policy command
2090  *		arg				Pointer to policy arguments
2091  *
2092  * Returns:	0				Success
2093  *		EINVAL				Invalid command or invalid policy arguments
2094  *
2095  */
2096 int
iopolicysys(struct proc * p,struct iopolicysys_args * uap,int32_t * retval)2097 iopolicysys(struct proc *p, struct iopolicysys_args *uap, int32_t *retval)
2098 {
2099 	int     error = 0;
2100 	struct _iopol_param_t iop_param;
2101 
2102 	if ((error = copyin(uap->arg, &iop_param, sizeof(iop_param))) != 0) {
2103 		goto out;
2104 	}
2105 
2106 #if CONFIG_MACF
2107 	error = mac_proc_check_iopolicysys(p, kauth_cred_get(),
2108 	    uap->cmd,
2109 	    iop_param.iop_iotype,
2110 	    iop_param.iop_scope,
2111 	    iop_param.iop_policy);
2112 	if (error) {
2113 		return error;
2114 	}
2115 #endif
2116 
2117 	switch (iop_param.iop_iotype) {
2118 	case IOPOL_TYPE_DISK:
2119 		error = iopolicysys_disk(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2120 		if (error == EIDRM) {
2121 			*retval = -2;
2122 			error = 0;
2123 		}
2124 		if (error) {
2125 			goto out;
2126 		}
2127 		break;
2128 	case IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY:
2129 		error = iopolicysys_vfs_hfs_case_sensitivity(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2130 		if (error) {
2131 			goto out;
2132 		}
2133 		break;
2134 	case IOPOL_TYPE_VFS_ATIME_UPDATES:
2135 		error = iopolicysys_vfs_atime_updates(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2136 		if (error) {
2137 			goto out;
2138 		}
2139 		break;
2140 	case IOPOL_TYPE_VFS_MATERIALIZE_DATALESS_FILES:
2141 #if !DEVELOPMENT
2142 		iop_param.iop_policy &= ~IOPOL_MATERIALIZE_DATALESS_FILES_ORIG;
2143 #endif
2144 		error = iopolicysys_vfs_materialize_dataless_files(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2145 		if (error) {
2146 			goto out;
2147 		}
2148 		break;
2149 	case IOPOL_TYPE_VFS_STATFS_NO_DATA_VOLUME:
2150 		error = iopolicysys_vfs_statfs_no_data_volume(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2151 		if (error) {
2152 			goto out;
2153 		}
2154 		break;
2155 	case IOPOL_TYPE_VFS_TRIGGER_RESOLVE:
2156 		error = iopolicysys_vfs_trigger_resolve(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2157 		if (error) {
2158 			goto out;
2159 		}
2160 		break;
2161 	case IOPOL_TYPE_VFS_IGNORE_CONTENT_PROTECTION:
2162 		error = iopolicysys_vfs_ignore_content_protection(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2163 		if (error) {
2164 			goto out;
2165 		}
2166 		break;
2167 	case IOPOL_TYPE_VFS_IGNORE_PERMISSIONS:
2168 		error = iopolicysys_vfs_ignore_node_permissions(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2169 		if (error) {
2170 			goto out;
2171 		}
2172 		break;
2173 	case IOPOL_TYPE_VFS_SKIP_MTIME_UPDATE:
2174 		error = iopolicysys_vfs_skip_mtime_update(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2175 		if (error) {
2176 			goto out;
2177 		}
2178 		break;
2179 	case IOPOL_TYPE_VFS_ALLOW_LOW_SPACE_WRITES:
2180 		error = iopolicysys_vfs_allow_lowspace_writes(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2181 		if (error) {
2182 			goto out;
2183 		}
2184 		break;
2185 	case IOPOL_TYPE_VFS_DISALLOW_RW_FOR_O_EVTONLY:
2186 		error = iopolicysys_vfs_disallow_rw_for_o_evtonly(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2187 		if (error) {
2188 			goto out;
2189 		}
2190 		break;
2191 	case IOPOL_TYPE_VFS_ALTLINK:
2192 		error = iopolicysys_vfs_altlink(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2193 		if (error) {
2194 			goto out;
2195 		}
2196 		break;
2197 	case IOPOL_TYPE_VFS_NOCACHE_WRITE_FS_BLKSIZE:
2198 		error = iopolicysys_vfs_nocache_write_fs_blksize(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2199 		if (error) {
2200 			goto out;
2201 		}
2202 		break;
2203 	case IOPOL_TYPE_VFS_SUPPORT_LONG_PATHS:
2204 		error = iopolicysys_vfs_support_long_paths(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2205 		if (error) {
2206 			goto out;
2207 		}
2208 		break;
2209 	case IOPOL_TYPE_VFS_ENTITLED_RESERVE_ACCESS:
2210 		error = iopolicysys_vfs_entitled_reserve_access(p, uap->cmd, iop_param.iop_scope, iop_param.iop_policy, &iop_param);
2211 		if (error) {
2212 			goto out;
2213 		}
2214 		break;
2215 
2216 	default:
2217 		error = EINVAL;
2218 		goto out;
2219 	}
2220 
2221 	/* Individual iotype handlers are expected to update iop_param, if requested with a GET command */
2222 	if (uap->cmd == IOPOL_CMD_GET) {
2223 		error = copyout((caddr_t)&iop_param, uap->arg, sizeof(iop_param));
2224 		if (error) {
2225 			goto out;
2226 		}
2227 	}
2228 
2229 out:
2230 	return error;
2231 }
2232 
2233 static int
iopolicysys_disk(struct proc * p __unused,int cmd,int scope,int policy,struct _iopol_param_t * iop_param)2234 iopolicysys_disk(struct proc *p __unused, int cmd, int scope, int policy, struct _iopol_param_t *iop_param)
2235 {
2236 	int                     error = 0;
2237 	thread_t        thread;
2238 	int                     policy_flavor;
2239 
2240 	/* Validate scope */
2241 	switch (scope) {
2242 	case IOPOL_SCOPE_PROCESS:
2243 		thread = THREAD_NULL;
2244 		policy_flavor = TASK_POLICY_IOPOL;
2245 		break;
2246 
2247 	case IOPOL_SCOPE_THREAD:
2248 		thread = current_thread();
2249 		policy_flavor = TASK_POLICY_IOPOL;
2250 
2251 		/* Not allowed to combine QoS and (non-PASSIVE) IO policy, doing so strips the QoS */
2252 		if (cmd == IOPOL_CMD_SET && thread_has_qos_policy(thread)) {
2253 			switch (policy) {
2254 			case IOPOL_DEFAULT:
2255 			case IOPOL_PASSIVE:
2256 				break;
2257 			case IOPOL_UTILITY:
2258 			case IOPOL_THROTTLE:
2259 			case IOPOL_IMPORTANT:
2260 			case IOPOL_STANDARD:
2261 				if (!thread_is_static_param(thread)) {
2262 					thread_remove_qos_policy(thread);
2263 					/*
2264 					 * This is not an error case, this is to return a marker to user-space that
2265 					 * we stripped the thread of its QoS class.
2266 					 */
2267 					error = EIDRM;
2268 					break;
2269 				}
2270 				OS_FALLTHROUGH;
2271 			default:
2272 				error = EINVAL;
2273 				goto out;
2274 			}
2275 		}
2276 		break;
2277 
2278 	case IOPOL_SCOPE_DARWIN_BG:
2279 #if !defined(XNU_TARGET_OS_OSX)
2280 		/* We don't want this on platforms outside of macOS as BG is always IOPOL_THROTTLE */
2281 		error = ENOTSUP;
2282 		goto out;
2283 #else /* !defined(XNU_TARGET_OS_OSX) */
2284 		thread = THREAD_NULL;
2285 		policy_flavor = TASK_POLICY_DARWIN_BG_IOPOL;
2286 		break;
2287 #endif /* !defined(XNU_TARGET_OS_OSX) */
2288 
2289 	default:
2290 		error = EINVAL;
2291 		goto out;
2292 	}
2293 
2294 	/* Validate policy */
2295 	if (cmd == IOPOL_CMD_SET) {
2296 		switch (policy) {
2297 		case IOPOL_DEFAULT:
2298 			if (scope == IOPOL_SCOPE_DARWIN_BG) {
2299 				/* the current default BG throttle level is UTILITY */
2300 				policy = IOPOL_UTILITY;
2301 			} else {
2302 				policy = IOPOL_IMPORTANT;
2303 			}
2304 			break;
2305 		case IOPOL_UTILITY:
2306 		/* fall-through */
2307 		case IOPOL_THROTTLE:
2308 			/* These levels are OK */
2309 			break;
2310 		case IOPOL_IMPORTANT:
2311 		/* fall-through */
2312 		case IOPOL_STANDARD:
2313 		/* fall-through */
2314 		case IOPOL_PASSIVE:
2315 			if (scope == IOPOL_SCOPE_DARWIN_BG) {
2316 				/* These levels are invalid for BG */
2317 				error = EINVAL;
2318 				goto out;
2319 			} else {
2320 				/* OK for other scopes */
2321 			}
2322 			break;
2323 		default:
2324 			error = EINVAL;
2325 			goto out;
2326 		}
2327 	}
2328 
2329 	/* Perform command */
2330 	switch (cmd) {
2331 	case IOPOL_CMD_SET:
2332 		if (thread != THREAD_NULL) {
2333 			proc_set_thread_policy(thread, TASK_POLICY_INTERNAL, policy_flavor, policy);
2334 		} else {
2335 			proc_set_task_policy(current_task(), TASK_POLICY_INTERNAL, policy_flavor, policy);
2336 		}
2337 		break;
2338 	case IOPOL_CMD_GET:
2339 		if (thread != THREAD_NULL) {
2340 			policy = proc_get_thread_policy(thread, TASK_POLICY_INTERNAL, policy_flavor);
2341 		} else {
2342 			policy = proc_get_task_policy(current_task(), TASK_POLICY_INTERNAL, policy_flavor);
2343 		}
2344 		iop_param->iop_policy = policy;
2345 		break;
2346 	default:
2347 		error = EINVAL;         /* unknown command */
2348 		break;
2349 	}
2350 
2351 out:
2352 	return error;
2353 }
2354 
2355 static int
iopolicysys_vfs_hfs_case_sensitivity(struct proc * p,int cmd,int scope,int policy,struct _iopol_param_t * iop_param)2356 iopolicysys_vfs_hfs_case_sensitivity(struct proc *p, int cmd, int scope, int policy, struct _iopol_param_t *iop_param)
2357 {
2358 	int                     error = 0;
2359 
2360 	/* Validate scope */
2361 	switch (scope) {
2362 	case IOPOL_SCOPE_PROCESS:
2363 		/* Only process OK */
2364 		break;
2365 	default:
2366 		error = EINVAL;
2367 		goto out;
2368 	}
2369 
2370 	/* Validate policy */
2371 	if (cmd == IOPOL_CMD_SET) {
2372 		switch (policy) {
2373 		case IOPOL_VFS_HFS_CASE_SENSITIVITY_DEFAULT:
2374 		/* fall-through */
2375 		case IOPOL_VFS_HFS_CASE_SENSITIVITY_FORCE_CASE_SENSITIVE:
2376 			/* These policies are OK */
2377 			break;
2378 		default:
2379 			error = EINVAL;
2380 			goto out;
2381 		}
2382 	}
2383 
2384 	/* Perform command */
2385 	switch (cmd) {
2386 	case IOPOL_CMD_SET:
2387 		if (0 == kauth_cred_issuser(kauth_cred_get())) {
2388 			/* If it's a non-root process, it needs to have the entitlement to set the policy */
2389 			boolean_t entitled = FALSE;
2390 			entitled = IOCurrentTaskHasEntitlement("com.apple.private.iopol.case_sensitivity");
2391 			if (!entitled) {
2392 				error = EPERM;
2393 				goto out;
2394 			}
2395 		}
2396 
2397 		switch (policy) {
2398 		case IOPOL_VFS_HFS_CASE_SENSITIVITY_DEFAULT:
2399 			OSBitAndAtomic16(~((uint32_t)P_VFS_IOPOLICY_FORCE_HFS_CASE_SENSITIVITY), &p->p_vfs_iopolicy);
2400 			break;
2401 		case IOPOL_VFS_HFS_CASE_SENSITIVITY_FORCE_CASE_SENSITIVE:
2402 			OSBitOrAtomic16((uint32_t)P_VFS_IOPOLICY_FORCE_HFS_CASE_SENSITIVITY, &p->p_vfs_iopolicy);
2403 			break;
2404 		default:
2405 			error = EINVAL;
2406 			goto out;
2407 		}
2408 
2409 		break;
2410 	case IOPOL_CMD_GET:
2411 		iop_param->iop_policy = (p->p_vfs_iopolicy & P_VFS_IOPOLICY_FORCE_HFS_CASE_SENSITIVITY)
2412 		    ? IOPOL_VFS_HFS_CASE_SENSITIVITY_FORCE_CASE_SENSITIVE
2413 		    : IOPOL_VFS_HFS_CASE_SENSITIVITY_DEFAULT;
2414 		break;
2415 	default:
2416 		error = EINVAL;         /* unknown command */
2417 		break;
2418 	}
2419 
2420 out:
2421 	return error;
2422 }
2423 
2424 static inline int
get_thread_atime_policy(struct uthread * ut)2425 get_thread_atime_policy(struct uthread *ut)
2426 {
2427 	return (ut->uu_flag & UT_ATIME_UPDATE) ? IOPOL_ATIME_UPDATES_OFF : IOPOL_ATIME_UPDATES_DEFAULT;
2428 }
2429 
2430 static inline void
set_thread_atime_policy(struct uthread * ut,int policy)2431 set_thread_atime_policy(struct uthread *ut, int policy)
2432 {
2433 	if (policy == IOPOL_ATIME_UPDATES_OFF) {
2434 		ut->uu_flag |= UT_ATIME_UPDATE;
2435 	} else {
2436 		ut->uu_flag &= ~UT_ATIME_UPDATE;
2437 	}
2438 }
2439 
2440 static inline void
set_task_atime_policy(struct proc * p,int policy)2441 set_task_atime_policy(struct proc *p, int policy)
2442 {
2443 	if (policy == IOPOL_ATIME_UPDATES_OFF) {
2444 		OSBitOrAtomic16((uint16_t)P_VFS_IOPOLICY_ATIME_UPDATES, &p->p_vfs_iopolicy);
2445 	} else {
2446 		OSBitAndAtomic16(~((uint16_t)P_VFS_IOPOLICY_ATIME_UPDATES), &p->p_vfs_iopolicy);
2447 	}
2448 }
2449 
2450 static inline int
get_task_atime_policy(struct proc * p)2451 get_task_atime_policy(struct proc *p)
2452 {
2453 	return (p->p_vfs_iopolicy & P_VFS_IOPOLICY_ATIME_UPDATES) ? IOPOL_ATIME_UPDATES_OFF : IOPOL_ATIME_UPDATES_DEFAULT;
2454 }
2455 
2456 static int
iopolicysys_vfs_atime_updates(struct proc * p __unused,int cmd,int scope,int policy,struct _iopol_param_t * iop_param)2457 iopolicysys_vfs_atime_updates(struct proc *p __unused, int cmd, int scope, int policy, struct _iopol_param_t *iop_param)
2458 {
2459 	int                     error = 0;
2460 	thread_t                thread;
2461 
2462 	/* Validate scope */
2463 	switch (scope) {
2464 	case IOPOL_SCOPE_THREAD:
2465 		thread = current_thread();
2466 		break;
2467 	case IOPOL_SCOPE_PROCESS:
2468 		thread = THREAD_NULL;
2469 		break;
2470 	default:
2471 		error = EINVAL;
2472 		goto out;
2473 	}
2474 
2475 	/* Validate policy */
2476 	if (cmd == IOPOL_CMD_SET) {
2477 		switch (policy) {
2478 		case IOPOL_ATIME_UPDATES_DEFAULT:
2479 		case IOPOL_ATIME_UPDATES_OFF:
2480 			break;
2481 		default:
2482 			error = EINVAL;
2483 			goto out;
2484 		}
2485 	}
2486 
2487 	/* Perform command */
2488 	switch (cmd) {
2489 	case IOPOL_CMD_SET:
2490 		if (thread != THREAD_NULL) {
2491 			set_thread_atime_policy(get_bsdthread_info(thread), policy);
2492 		} else {
2493 			set_task_atime_policy(p, policy);
2494 		}
2495 		break;
2496 	case IOPOL_CMD_GET:
2497 		if (thread != THREAD_NULL) {
2498 			policy = get_thread_atime_policy(get_bsdthread_info(thread));
2499 		} else {
2500 			policy = get_task_atime_policy(p);
2501 		}
2502 		iop_param->iop_policy = policy;
2503 		break;
2504 	default:
2505 		error = EINVAL;         /* unknown command */
2506 		break;
2507 	}
2508 
2509 out:
2510 	return error;
2511 }
2512 
2513 static inline int
get_thread_materialize_policy(struct uthread * ut)2514 get_thread_materialize_policy(struct uthread *ut)
2515 {
2516 	if (ut->uu_flag & UT_NSPACE_NODATALESSFAULTS) {
2517 		return IOPOL_MATERIALIZE_DATALESS_FILES_OFF;
2518 	} else if (ut->uu_flag & UT_NSPACE_FORCEDATALESSFAULTS) {
2519 		return IOPOL_MATERIALIZE_DATALESS_FILES_ON;
2520 	}
2521 	/* Default thread behavior is "inherit process behavior". */
2522 	return IOPOL_MATERIALIZE_DATALESS_FILES_DEFAULT;
2523 }
2524 
2525 static inline void
set_thread_materialize_policy(struct uthread * ut,int policy)2526 set_thread_materialize_policy(struct uthread *ut, int policy)
2527 {
2528 	if (policy == IOPOL_MATERIALIZE_DATALESS_FILES_OFF) {
2529 		ut->uu_flag &= ~UT_NSPACE_FORCEDATALESSFAULTS;
2530 		ut->uu_flag |= UT_NSPACE_NODATALESSFAULTS;
2531 	} else if (policy == IOPOL_MATERIALIZE_DATALESS_FILES_ON) {
2532 		ut->uu_flag &= ~UT_NSPACE_NODATALESSFAULTS;
2533 		ut->uu_flag |= UT_NSPACE_FORCEDATALESSFAULTS;
2534 	} else {
2535 		ut->uu_flag &= ~(UT_NSPACE_NODATALESSFAULTS | UT_NSPACE_FORCEDATALESSFAULTS);
2536 	}
2537 }
2538 
2539 static inline void
set_proc_materialize_policy(struct proc * p,int policy)2540 set_proc_materialize_policy(struct proc *p, int policy)
2541 {
2542 	int policy_basic = (policy & IOPOL_MATERIALIZE_DATALESS_FILES_BASIC_MASK);
2543 
2544 	if (policy_basic == IOPOL_MATERIALIZE_DATALESS_FILES_DEFAULT) {
2545 		/*
2546 		 * Caller has specified "use the default policy".
2547 		 * The default policy is to NOT materialize dataless
2548 		 * files.
2549 		 */
2550 		policy_basic = IOPOL_MATERIALIZE_DATALESS_FILES_OFF;
2551 	}
2552 	if (policy_basic == IOPOL_MATERIALIZE_DATALESS_FILES_ON) {
2553 		OSBitOrAtomic16((uint16_t)P_VFS_IOPOLICY_MATERIALIZE_DATALESS_FILES, &p->p_vfs_iopolicy);
2554 		if (policy & IOPOL_MATERIALIZE_DATALESS_FILES_ORIG) {
2555 			OSBitOrAtomic16((uint16_t)P_VFS_IOPOLICY_MATERIALIZE_DATALESS_FILES_ORIG, &p->p_vfs_iopolicy);
2556 		}
2557 	} else {
2558 		OSBitAndAtomic16(~((uint16_t)P_VFS_IOPOLICY_MATERIALIZE_DATALESS_FILES), &p->p_vfs_iopolicy);
2559 		if (policy & IOPOL_MATERIALIZE_DATALESS_FILES_ORIG) {
2560 			OSBitAndAtomic16(~(uint16_t)P_VFS_IOPOLICY_MATERIALIZE_DATALESS_FILES_ORIG, &p->p_vfs_iopolicy);
2561 		}
2562 	}
2563 }
2564 
2565 static int
get_proc_materialize_policy(struct proc * p)2566 get_proc_materialize_policy(struct proc *p)
2567 {
2568 	return (p->p_vfs_iopolicy & P_VFS_IOPOLICY_MATERIALIZE_DATALESS_FILES) ? IOPOL_MATERIALIZE_DATALESS_FILES_ON : IOPOL_MATERIALIZE_DATALESS_FILES_OFF;
2569 }
2570 
2571 int
iopolicysys_vfs_materialize_dataless_files(struct proc * p __unused,int cmd,int scope,int policy,struct _iopol_param_t * iop_param)2572 iopolicysys_vfs_materialize_dataless_files(struct proc *p __unused, int cmd, int scope, int policy, struct _iopol_param_t *iop_param)
2573 {
2574 	int                     error = 0;
2575 	thread_t                thread;
2576 
2577 	/* Validate scope */
2578 	switch (scope) {
2579 	case IOPOL_SCOPE_THREAD:
2580 		thread = current_thread();
2581 		break;
2582 	case IOPOL_SCOPE_PROCESS:
2583 		thread = THREAD_NULL;
2584 		break;
2585 	default:
2586 		error = EINVAL;
2587 		goto out;
2588 	}
2589 
2590 	/* Validate policy */
2591 	if (cmd == IOPOL_CMD_SET) {
2592 		int dataless_policy = policy & IOPOL_MATERIALIZE_DATALESS_FILES_BASIC_MASK;
2593 		switch (dataless_policy) {
2594 		case IOPOL_MATERIALIZE_DATALESS_FILES_DEFAULT:
2595 		case IOPOL_MATERIALIZE_DATALESS_FILES_OFF:
2596 		case IOPOL_MATERIALIZE_DATALESS_FILES_ON:
2597 			break;
2598 		default:
2599 			error = EINVAL;
2600 			goto out;
2601 		}
2602 	}
2603 
2604 	/* Perform command */
2605 	switch (cmd) {
2606 	case IOPOL_CMD_SET: {
2607 		int dataless_policy = policy & IOPOL_MATERIALIZE_DATALESS_FILES_BASIC_MASK;
2608 		if (thread != THREAD_NULL) {
2609 			set_thread_materialize_policy(get_bsdthread_info(thread), dataless_policy);
2610 		} else {
2611 			set_proc_materialize_policy(p, policy);
2612 		}
2613 		break;
2614 	}
2615 	case IOPOL_CMD_GET:
2616 		if (thread != THREAD_NULL) {
2617 			policy = get_thread_materialize_policy(get_bsdthread_info(thread));
2618 		} else {
2619 			policy = get_proc_materialize_policy(p);
2620 		}
2621 		iop_param->iop_policy = policy;
2622 		break;
2623 	default:
2624 		error = EINVAL;         /* unknown command */
2625 		break;
2626 	}
2627 
2628 out:
2629 	return error;
2630 }
2631 
2632 static int
iopolicysys_vfs_statfs_no_data_volume(struct proc * p __unused,int cmd,int scope,int policy,struct _iopol_param_t * iop_param)2633 iopolicysys_vfs_statfs_no_data_volume(struct proc *p __unused, int cmd,
2634     int scope, int policy, struct _iopol_param_t *iop_param)
2635 {
2636 	int error = 0;
2637 
2638 	/* Validate scope */
2639 	switch (scope) {
2640 	case IOPOL_SCOPE_PROCESS:
2641 		/* Only process OK */
2642 		break;
2643 	default:
2644 		error = EINVAL;
2645 		goto out;
2646 	}
2647 
2648 	/* Validate policy */
2649 	if (cmd == IOPOL_CMD_SET) {
2650 		switch (policy) {
2651 		case IOPOL_VFS_STATFS_NO_DATA_VOLUME_DEFAULT:
2652 		/* fall-through */
2653 		case IOPOL_VFS_STATFS_FORCE_NO_DATA_VOLUME:
2654 			/* These policies are OK */
2655 			break;
2656 		default:
2657 			error = EINVAL;
2658 			goto out;
2659 		}
2660 	}
2661 
2662 	/* Perform command */
2663 	switch (cmd) {
2664 	case IOPOL_CMD_SET:
2665 		if (0 == kauth_cred_issuser(kauth_cred_get())) {
2666 			/* If it's a non-root process, it needs to have the entitlement to set the policy */
2667 			boolean_t entitled = FALSE;
2668 			entitled = IOCurrentTaskHasEntitlement("com.apple.private.iopol.case_sensitivity");
2669 			if (!entitled) {
2670 				error = EPERM;
2671 				goto out;
2672 			}
2673 		}
2674 
2675 		switch (policy) {
2676 		case IOPOL_VFS_STATFS_NO_DATA_VOLUME_DEFAULT:
2677 			OSBitAndAtomic16(~((uint32_t)P_VFS_IOPOLICY_STATFS_NO_DATA_VOLUME), &p->p_vfs_iopolicy);
2678 			break;
2679 		case IOPOL_VFS_STATFS_FORCE_NO_DATA_VOLUME:
2680 			OSBitOrAtomic16((uint32_t)P_VFS_IOPOLICY_STATFS_NO_DATA_VOLUME, &p->p_vfs_iopolicy);
2681 			break;
2682 		default:
2683 			error = EINVAL;
2684 			goto out;
2685 		}
2686 
2687 		break;
2688 	case IOPOL_CMD_GET:
2689 		iop_param->iop_policy = (p->p_vfs_iopolicy & P_VFS_IOPOLICY_STATFS_NO_DATA_VOLUME)
2690 		    ? IOPOL_VFS_STATFS_FORCE_NO_DATA_VOLUME
2691 		    : IOPOL_VFS_STATFS_NO_DATA_VOLUME_DEFAULT;
2692 		break;
2693 	default:
2694 		error = EINVAL;         /* unknown command */
2695 		break;
2696 	}
2697 
2698 out:
2699 	return error;
2700 }
2701 
2702 static int
iopolicysys_vfs_trigger_resolve(struct proc * p __unused,int cmd,int scope,int policy,struct _iopol_param_t * iop_param)2703 iopolicysys_vfs_trigger_resolve(struct proc *p __unused, int cmd,
2704     int scope, int policy, struct _iopol_param_t *iop_param)
2705 {
2706 	int error = 0;
2707 
2708 	/* Validate scope */
2709 	switch (scope) {
2710 	case IOPOL_SCOPE_PROCESS:
2711 		/* Only process OK */
2712 		break;
2713 	default:
2714 		error = EINVAL;
2715 		goto out;
2716 	}
2717 
2718 	/* Validate policy */
2719 	if (cmd == IOPOL_CMD_SET) {
2720 		switch (policy) {
2721 		case IOPOL_VFS_TRIGGER_RESOLVE_DEFAULT:
2722 		/* fall-through */
2723 		case IOPOL_VFS_TRIGGER_RESOLVE_OFF:
2724 			/* These policies are OK */
2725 			break;
2726 		default:
2727 			error = EINVAL;
2728 			goto out;
2729 		}
2730 	}
2731 
2732 	/* Perform command */
2733 	switch (cmd) {
2734 	case IOPOL_CMD_SET:
2735 		switch (policy) {
2736 		case IOPOL_VFS_TRIGGER_RESOLVE_DEFAULT:
2737 			OSBitAndAtomic16(~((uint32_t)P_VFS_IOPOLICY_TRIGGER_RESOLVE_DISABLE), &p->p_vfs_iopolicy);
2738 			break;
2739 		case IOPOL_VFS_TRIGGER_RESOLVE_OFF:
2740 			OSBitOrAtomic16((uint32_t)P_VFS_IOPOLICY_TRIGGER_RESOLVE_DISABLE, &p->p_vfs_iopolicy);
2741 			break;
2742 		default:
2743 			error = EINVAL;
2744 			goto out;
2745 		}
2746 
2747 		break;
2748 	case IOPOL_CMD_GET:
2749 		iop_param->iop_policy = (p->p_vfs_iopolicy & P_VFS_IOPOLICY_TRIGGER_RESOLVE_DISABLE)
2750 		    ? IOPOL_VFS_TRIGGER_RESOLVE_OFF
2751 		    : IOPOL_VFS_TRIGGER_RESOLVE_DEFAULT;
2752 		break;
2753 	default:
2754 		error = EINVAL;         /* unknown command */
2755 		break;
2756 	}
2757 
2758 out:
2759 	return error;
2760 }
2761 
2762 static int
iopolicysys_vfs_ignore_content_protection(struct proc * p,int cmd,int scope,int policy,struct _iopol_param_t * iop_param)2763 iopolicysys_vfs_ignore_content_protection(struct proc *p, int cmd, int scope,
2764     int policy, struct _iopol_param_t *iop_param)
2765 {
2766 	int error = 0;
2767 
2768 	/* Validate scope */
2769 	switch (scope) {
2770 	case IOPOL_SCOPE_PROCESS:
2771 		/* Only process OK */
2772 		break;
2773 	default:
2774 		error = EINVAL;
2775 		goto out;
2776 	}
2777 
2778 	/* Validate policy */
2779 	if (cmd == IOPOL_CMD_SET) {
2780 		switch (policy) {
2781 		case IOPOL_VFS_CONTENT_PROTECTION_DEFAULT:
2782 			OS_FALLTHROUGH;
2783 		case IOPOL_VFS_CONTENT_PROTECTION_IGNORE:
2784 			/* These policies are OK */
2785 			break;
2786 		default:
2787 			error = EINVAL;
2788 			goto out;
2789 		}
2790 	}
2791 
2792 	/* Perform command */
2793 	switch (cmd) {
2794 	case IOPOL_CMD_SET:
2795 		if (0 == kauth_cred_issuser(kauth_cred_get())) {
2796 			/* If it's a non-root process, it needs to have the entitlement to set the policy */
2797 			boolean_t entitled = FALSE;
2798 			entitled = IOCurrentTaskHasEntitlement("com.apple.private.iopol.case_sensitivity");
2799 			if (!entitled) {
2800 				error = EPERM;
2801 				goto out;
2802 			}
2803 		}
2804 
2805 		switch (policy) {
2806 		case IOPOL_VFS_CONTENT_PROTECTION_DEFAULT:
2807 			os_atomic_andnot(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_IGNORE_CONTENT_PROTECTION, relaxed);
2808 			break;
2809 		case IOPOL_VFS_CONTENT_PROTECTION_IGNORE:
2810 			os_atomic_or(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_IGNORE_CONTENT_PROTECTION, relaxed);
2811 			break;
2812 		default:
2813 			error = EINVAL;
2814 			goto out;
2815 		}
2816 
2817 		break;
2818 	case IOPOL_CMD_GET:
2819 		iop_param->iop_policy = (os_atomic_load(&p->p_vfs_iopolicy, relaxed) & P_VFS_IOPOLICY_IGNORE_CONTENT_PROTECTION)
2820 		    ? IOPOL_VFS_CONTENT_PROTECTION_IGNORE
2821 		    : IOPOL_VFS_CONTENT_PROTECTION_DEFAULT;
2822 		break;
2823 	default:
2824 		error = EINVAL;         /* unknown command */
2825 		break;
2826 	}
2827 
2828 out:
2829 	return error;
2830 }
2831 
2832 static int
get_proc_vfs_ignore_permissions_policy(struct proc * p)2833 get_proc_vfs_ignore_permissions_policy(struct proc *p)
2834 {
2835 	return os_atomic_load(&p->p_vfs_iopolicy, relaxed) & P_VFS_IOPOLICY_IGNORE_NODE_PERMISSIONS ?
2836 	       IOPOL_VFS_IGNORE_PERMISSIONS_ON : IOPOL_VFS_IGNORE_PERMISSIONS_OFF;
2837 }
2838 
2839 static int
get_thread_vfs_ignore_permissions_policy(thread_t thread)2840 get_thread_vfs_ignore_permissions_policy(thread_t thread)
2841 {
2842 	struct uthread *ut = get_bsdthread_info(thread);
2843 
2844 	return (ut->uu_flag & UT_IGNORE_NODE_PERMISSIONS) ?
2845 	       IOPOL_VFS_IGNORE_PERMISSIONS_ON : IOPOL_VFS_IGNORE_PERMISSIONS_OFF;
2846 }
2847 
2848 static void
set_proc_vfs_ignore_permissions_policy(struct proc * p,int policy)2849 set_proc_vfs_ignore_permissions_policy(struct proc *p, int policy)
2850 {
2851 	switch (policy) {
2852 	case IOPOL_VFS_IGNORE_PERMISSIONS_OFF:
2853 		os_atomic_andnot(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_IGNORE_NODE_PERMISSIONS, relaxed);
2854 		break;
2855 	case IOPOL_VFS_IGNORE_PERMISSIONS_ON:
2856 		os_atomic_or(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_IGNORE_NODE_PERMISSIONS, relaxed);
2857 		break;
2858 	default:
2859 		break;
2860 	}
2861 }
2862 
2863 static void
set_thread_vfs_ignore_permissions_policy(thread_t thread,int policy)2864 set_thread_vfs_ignore_permissions_policy(thread_t thread, int policy)
2865 {
2866 	struct uthread *ut = get_bsdthread_info(thread);
2867 
2868 	switch (policy) {
2869 	case IOPOL_VFS_IGNORE_PERMISSIONS_OFF:
2870 		ut->uu_flag &= ~UT_IGNORE_NODE_PERMISSIONS;
2871 		break;
2872 	case IOPOL_VFS_IGNORE_PERMISSIONS_ON:
2873 		ut->uu_flag |= UT_IGNORE_NODE_PERMISSIONS;
2874 		break;
2875 	default:
2876 		break;
2877 	}
2878 }
2879 
2880 #define AUTHORIZED_ACCESS_ENTITLEMENT \
2881 	"com.apple.private.vfs.authorized-access"
2882 int
iopolicysys_vfs_ignore_node_permissions(struct proc * p,int cmd,int scope,int policy,__unused struct _iopol_param_t * iop_param)2883 iopolicysys_vfs_ignore_node_permissions(struct proc *p, int cmd, int scope,
2884     int policy, __unused struct _iopol_param_t *iop_param)
2885 {
2886 	int error = EINVAL;
2887 	thread_t thread = THREAD_NULL;
2888 
2889 	switch (scope) {
2890 	case IOPOL_SCOPE_THREAD:
2891 		thread = current_thread();
2892 		break;
2893 	case IOPOL_SCOPE_PROCESS:
2894 		break;
2895 	default:
2896 		goto out;
2897 	}
2898 
2899 	switch (cmd) {
2900 	case IOPOL_CMD_GET:
2901 		if (thread != THREAD_NULL) {
2902 			policy = get_thread_vfs_ignore_permissions_policy(thread);
2903 		} else {
2904 			policy = get_proc_vfs_ignore_permissions_policy(p);
2905 		}
2906 		iop_param->iop_policy = policy;
2907 		goto out_ok;
2908 	case IOPOL_CMD_SET:
2909 		/* SET is handled after the switch */
2910 		break;
2911 	default:
2912 		goto out;
2913 	}
2914 
2915 	if (!IOCurrentTaskHasEntitlement(AUTHORIZED_ACCESS_ENTITLEMENT)) {
2916 		error = EPERM;
2917 		goto out;
2918 	}
2919 
2920 	if (thread != THREAD_NULL) {
2921 		set_thread_vfs_ignore_permissions_policy(thread, policy);
2922 	} else {
2923 		set_proc_vfs_ignore_permissions_policy(p, policy);
2924 	}
2925 
2926 out_ok:
2927 	error = 0;
2928 out:
2929 	return error;
2930 }
2931 
2932 static inline void
set_thread_skip_mtime_policy(struct uthread * ut,int policy)2933 set_thread_skip_mtime_policy(struct uthread *ut, int policy)
2934 {
2935 	os_atomic_andnot(&ut->uu_flag, UT_SKIP_MTIME_UPDATE |
2936 	    UT_SKIP_MTIME_UPDATE_IGNORE, relaxed);
2937 
2938 	if (policy == IOPOL_VFS_SKIP_MTIME_UPDATE_ON) {
2939 		os_atomic_or(&ut->uu_flag, UT_SKIP_MTIME_UPDATE, relaxed);
2940 	} else if (policy == IOPOL_VFS_SKIP_MTIME_UPDATE_IGNORE) {
2941 		os_atomic_or(&ut->uu_flag, UT_SKIP_MTIME_UPDATE_IGNORE, relaxed);
2942 	}
2943 }
2944 
2945 static inline int
get_thread_skip_mtime_policy(struct uthread * ut)2946 get_thread_skip_mtime_policy(struct uthread *ut)
2947 {
2948 	return (os_atomic_load(&ut->uu_flag, relaxed) & UT_SKIP_MTIME_UPDATE) ?
2949 	       IOPOL_VFS_SKIP_MTIME_UPDATE_ON : IOPOL_VFS_SKIP_MTIME_UPDATE_OFF;
2950 }
2951 
2952 static inline void
set_proc_skip_mtime_policy(struct proc * p,int policy)2953 set_proc_skip_mtime_policy(struct proc *p, int policy)
2954 {
2955 	if (policy == IOPOL_VFS_SKIP_MTIME_UPDATE_ON) {
2956 		os_atomic_or(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_SKIP_MTIME_UPDATE, relaxed);
2957 	} else {
2958 		os_atomic_andnot(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_SKIP_MTIME_UPDATE, relaxed);
2959 	}
2960 }
2961 
2962 static inline int
get_proc_skip_mtime_policy(struct proc * p)2963 get_proc_skip_mtime_policy(struct proc *p)
2964 {
2965 	return (os_atomic_load(&p->p_vfs_iopolicy, relaxed) & P_VFS_IOPOLICY_SKIP_MTIME_UPDATE) ?
2966 	       IOPOL_VFS_SKIP_MTIME_UPDATE_ON : IOPOL_VFS_SKIP_MTIME_UPDATE_OFF;
2967 }
2968 
2969 #define SKIP_MTIME_UPDATE_ENTITLEMENT \
2970 	"com.apple.private.vfs.skip-mtime-updates"
2971 int
iopolicysys_vfs_skip_mtime_update(struct proc * p,int cmd,int scope,int policy,__unused struct _iopol_param_t * iop_param)2972 iopolicysys_vfs_skip_mtime_update(struct proc *p, int cmd, int scope,
2973     int policy, __unused struct _iopol_param_t *iop_param)
2974 {
2975 	thread_t thread;
2976 	int error = 0;
2977 
2978 	/* Validate scope */
2979 	switch (scope) {
2980 	case IOPOL_SCOPE_THREAD:
2981 		thread = current_thread();
2982 		break;
2983 	case IOPOL_SCOPE_PROCESS:
2984 		thread = THREAD_NULL;
2985 		break;
2986 	default:
2987 		error = EINVAL;
2988 		goto out;
2989 	}
2990 
2991 	/* Validate policy */
2992 	if (cmd == IOPOL_CMD_SET) {
2993 		switch (policy) {
2994 		case IOPOL_VFS_SKIP_MTIME_UPDATE_ON:
2995 		case IOPOL_VFS_SKIP_MTIME_UPDATE_OFF:
2996 		case IOPOL_VFS_SKIP_MTIME_UPDATE_IGNORE:
2997 			if (!IOCurrentTaskHasEntitlement(SKIP_MTIME_UPDATE_ENTITLEMENT)) {
2998 				error = EPERM;
2999 				goto out;
3000 			}
3001 			break;
3002 		default:
3003 			error = EINVAL;
3004 			goto out;
3005 		}
3006 	}
3007 
3008 	/* Perform command */
3009 	switch (cmd) {
3010 	case IOPOL_CMD_SET:
3011 		if (thread != THREAD_NULL) {
3012 			set_thread_skip_mtime_policy(get_bsdthread_info(thread), policy);
3013 		} else {
3014 			/*
3015 			 * The 'IOPOL_VFS_SKIP_MTIME_UPDATE_IGNORE' policy is only
3016 			 * applicable for thread.
3017 			 */
3018 			if (policy == IOPOL_VFS_SKIP_MTIME_UPDATE_IGNORE) {
3019 				error = EINVAL;
3020 				goto out;
3021 			}
3022 			set_proc_skip_mtime_policy(p, policy);
3023 		}
3024 		break;
3025 	case IOPOL_CMD_GET:
3026 		if (thread != THREAD_NULL) {
3027 			policy = get_thread_skip_mtime_policy(get_bsdthread_info(thread));
3028 		} else {
3029 			policy = get_proc_skip_mtime_policy(p);
3030 		}
3031 		iop_param->iop_policy = policy;
3032 		break;
3033 	default:
3034 		error = EINVAL;         /* unknown command */
3035 		break;
3036 	}
3037 
3038 out:
3039 	return error;
3040 }
3041 
3042 #define ALLOW_LOW_SPACE_WRITES_ENTITLEMENT \
3043 	"com.apple.private.vfs.allow-low-space-writes"
3044 static int
iopolicysys_vfs_allow_lowspace_writes(struct proc * p,int cmd,int scope,int policy,__unused struct _iopol_param_t * iop_param)3045 iopolicysys_vfs_allow_lowspace_writes(struct proc *p, int cmd, int scope,
3046     int policy, __unused struct _iopol_param_t *iop_param)
3047 {
3048 	int error = EINVAL;
3049 
3050 	switch (scope) {
3051 	case IOPOL_SCOPE_PROCESS:
3052 		break;
3053 	default:
3054 		goto out;
3055 	}
3056 
3057 	switch (cmd) {
3058 	case IOPOL_CMD_GET:
3059 		policy = os_atomic_load(&p->p_vfs_iopolicy, relaxed) & P_VFS_IOPOLICY_ALLOW_LOW_SPACE_WRITES ?
3060 		    IOPOL_VFS_ALLOW_LOW_SPACE_WRITES_ON : IOPOL_VFS_ALLOW_LOW_SPACE_WRITES_OFF;
3061 		iop_param->iop_policy = policy;
3062 		goto out_ok;
3063 	case IOPOL_CMD_SET:
3064 		break;
3065 	default:
3066 		break;
3067 	}
3068 
3069 	if (!IOCurrentTaskHasEntitlement(ALLOW_LOW_SPACE_WRITES_ENTITLEMENT)) {
3070 		error = EPERM;
3071 		goto out;
3072 	}
3073 
3074 	switch (policy) {
3075 	case IOPOL_VFS_ALLOW_LOW_SPACE_WRITES_OFF:
3076 		os_atomic_andnot(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_ALLOW_LOW_SPACE_WRITES, relaxed);
3077 		break;
3078 	case IOPOL_VFS_ALLOW_LOW_SPACE_WRITES_ON:
3079 		os_atomic_or(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_ALLOW_LOW_SPACE_WRITES, relaxed);
3080 		break;
3081 	default:
3082 		break;
3083 	}
3084 
3085 out_ok:
3086 	error = 0;
3087 out:
3088 	return error;
3089 }
3090 
3091 #define DISALLOW_RW_FOR_O_EVTONLY_ENTITLEMENT \
3092 	"com.apple.private.vfs.disallow-rw-for-o-evtonly"
3093 
3094 static int
iopolicysys_vfs_disallow_rw_for_o_evtonly(struct proc * p,int cmd,int scope,int policy,__unused struct _iopol_param_t * iop_param)3095 iopolicysys_vfs_disallow_rw_for_o_evtonly(struct proc *p, int cmd, int scope,
3096     int policy, __unused struct _iopol_param_t *iop_param)
3097 {
3098 	int error = EINVAL;
3099 
3100 	switch (scope) {
3101 	case IOPOL_SCOPE_PROCESS:
3102 		break;
3103 	default:
3104 		goto out;
3105 	}
3106 
3107 	switch (cmd) {
3108 	case IOPOL_CMD_GET:
3109 		policy = (os_atomic_load(&p->p_vfs_iopolicy, relaxed) &
3110 		    P_VFS_IOPOLICY_DISALLOW_RW_FOR_O_EVTONLY) ?
3111 		    IOPOL_VFS_DISALLOW_RW_FOR_O_EVTONLY_ON :
3112 		    IOPOL_VFS_DISALLOW_RW_FOR_O_EVTONLY_DEFAULT;
3113 		iop_param->iop_policy = policy;
3114 		goto out_ok;
3115 	case IOPOL_CMD_SET:
3116 		break;
3117 	default:
3118 		goto out;
3119 	}
3120 
3121 	if (!IOCurrentTaskHasEntitlement(DISALLOW_RW_FOR_O_EVTONLY_ENTITLEMENT)) {
3122 		error = EPERM;
3123 		goto out;
3124 	}
3125 
3126 	/* Once set, we don't allow the process to clear it. */
3127 	switch (policy) {
3128 	case IOPOL_VFS_DISALLOW_RW_FOR_O_EVTONLY_ON:
3129 		os_atomic_or(&p->p_vfs_iopolicy,
3130 		    P_VFS_IOPOLICY_DISALLOW_RW_FOR_O_EVTONLY, relaxed);
3131 		break;
3132 	default:
3133 		goto out;
3134 	}
3135 
3136 out_ok:
3137 	error = 0;
3138 out:
3139 	return error;
3140 }
3141 
3142 static int
iopolicysys_vfs_altlink(struct proc * p,int cmd,int scope,int policy,struct _iopol_param_t * iop_param)3143 iopolicysys_vfs_altlink(struct proc *p, int cmd, int scope, int policy,
3144     struct _iopol_param_t *iop_param)
3145 {
3146 	if (scope != IOPOL_SCOPE_PROCESS) {
3147 		return EINVAL;
3148 	}
3149 
3150 	if (cmd == IOPOL_CMD_GET) {
3151 		policy = (os_atomic_load(&p->p_vfs_iopolicy, relaxed) & P_VFS_IOPOLICY_ALTLINK) ?
3152 		    IOPOL_VFS_ALTLINK_ENABLED : IOPOL_VFS_ALTLINK_DISABLED;
3153 		iop_param->iop_policy = policy;
3154 		return 0;
3155 	}
3156 
3157 	/* Once set, we don't allow the process to clear it. */
3158 	if (policy == IOPOL_VFS_ALTLINK_ENABLED) {
3159 		os_atomic_or(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_ALTLINK, relaxed);
3160 		return 0;
3161 	}
3162 
3163 	return EINVAL;
3164 }
3165 
3166 static int
iopolicysys_vfs_nocache_write_fs_blksize(struct proc * p,int cmd,int scope,int policy,struct _iopol_param_t * iop_param)3167 iopolicysys_vfs_nocache_write_fs_blksize(struct proc *p, int cmd, int scope, int policy,
3168     struct _iopol_param_t *iop_param)
3169 {
3170 	if (scope != IOPOL_SCOPE_PROCESS) {
3171 		return EINVAL;
3172 	}
3173 
3174 	if (cmd == IOPOL_CMD_GET) {
3175 		policy = (os_atomic_load(&p->p_vfs_iopolicy, relaxed) & P_VFS_IOPOLICY_NOCACHE_WRITE_FS_BLKSIZE) ?
3176 		    IOPOL_VFS_NOCACHE_WRITE_FS_BLKSIZE_ON : IOPOL_VFS_NOCACHE_WRITE_FS_BLKSIZE_DEFAULT;
3177 		iop_param->iop_policy = policy;
3178 		return 0;
3179 	}
3180 
3181 	/* Once set, we don't allow the process to clear it. */
3182 	if (policy == IOPOL_VFS_NOCACHE_WRITE_FS_BLKSIZE_ON) {
3183 		os_atomic_or(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_NOCACHE_WRITE_FS_BLKSIZE, relaxed);
3184 		return 0;
3185 	}
3186 
3187 	return EINVAL;
3188 }
3189 
3190 static inline void
set_thread_support_long_paths(struct uthread * ut,int policy)3191 set_thread_support_long_paths(struct uthread *ut, int policy)
3192 {
3193 	if (policy == IOPOL_VFS_SUPPORT_LONG_PATHS_ON) {
3194 		os_atomic_or(&ut->uu_flag, UT_SUPPORT_LONG_PATHS, relaxed);
3195 	} else {
3196 		os_atomic_andnot(&ut->uu_flag, UT_SUPPORT_LONG_PATHS, relaxed);
3197 	}
3198 }
3199 
3200 static inline int
get_thread_support_long_paths(struct uthread * ut)3201 get_thread_support_long_paths(struct uthread *ut)
3202 {
3203 	return (os_atomic_load(&ut->uu_flag, relaxed) & UT_SUPPORT_LONG_PATHS) ?
3204 	       IOPOL_VFS_SUPPORT_LONG_PATHS_ON : IOPOL_VFS_SUPPORT_LONG_PATHS_DEFAULT;
3205 }
3206 
3207 static inline void
set_proc_support_long_paths(struct proc * p,int policy)3208 set_proc_support_long_paths(struct proc *p, int policy)
3209 {
3210 	if (policy == IOPOL_VFS_SUPPORT_LONG_PATHS_ON) {
3211 		os_atomic_or(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_SUPPORT_LONG_PATHS, relaxed);
3212 	} else {
3213 		os_atomic_andnot(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_SUPPORT_LONG_PATHS, relaxed);
3214 	}
3215 }
3216 
3217 static inline int
get_proc_support_long_paths(struct proc * p)3218 get_proc_support_long_paths(struct proc *p)
3219 {
3220 	return (os_atomic_load(&p->p_vfs_iopolicy, relaxed) & P_VFS_IOPOLICY_SUPPORT_LONG_PATHS) ?
3221 	       IOPOL_VFS_SUPPORT_LONG_PATHS_ON : IOPOL_VFS_SUPPORT_LONG_PATHS_DEFAULT;
3222 }
3223 
3224 #define SUPPORT_LONG_PATHS_ENTITLEMENT \
3225 	"com.apple.private.vfs.support-long-paths"
3226 
3227 static int
iopolicysys_vfs_support_long_paths(struct proc * p,int cmd,int scope,int policy,struct _iopol_param_t * iop_param)3228 iopolicysys_vfs_support_long_paths(struct proc *p, int cmd, int scope,
3229     int policy, struct _iopol_param_t *iop_param)
3230 {
3231 	thread_t thread;
3232 	int error = 0;
3233 
3234 	/* Validate scope */
3235 	switch (scope) {
3236 	case IOPOL_SCOPE_THREAD:
3237 		thread = current_thread();
3238 		break;
3239 	case IOPOL_SCOPE_PROCESS:
3240 		thread = THREAD_NULL;
3241 		break;
3242 	default:
3243 		error = EINVAL;
3244 		goto out;
3245 	}
3246 
3247 	/* Validate policy */
3248 	if (cmd == IOPOL_CMD_SET) {
3249 		switch (policy) {
3250 		case IOPOL_VFS_SUPPORT_LONG_PATHS_DEFAULT:
3251 		case IOPOL_VFS_SUPPORT_LONG_PATHS_ON:
3252 			if (!IOCurrentTaskHasEntitlement(SUPPORT_LONG_PATHS_ENTITLEMENT)) {
3253 				error = EPERM;
3254 				goto out;
3255 			}
3256 			break;
3257 		default:
3258 			error = EINVAL;
3259 			goto out;
3260 		}
3261 	}
3262 
3263 	/* Perform command */
3264 	switch (cmd) {
3265 	case IOPOL_CMD_SET:
3266 		if (thread != THREAD_NULL) {
3267 			set_thread_support_long_paths(get_bsdthread_info(thread), policy);
3268 		} else {
3269 			set_proc_support_long_paths(p, policy);
3270 		}
3271 		break;
3272 	case IOPOL_CMD_GET:
3273 		if (thread != THREAD_NULL) {
3274 			policy = get_thread_support_long_paths(get_bsdthread_info(thread));
3275 		} else {
3276 			policy = get_proc_support_long_paths(p);
3277 		}
3278 		iop_param->iop_policy = policy;
3279 		break;
3280 	default:
3281 		error = EINVAL;         /* unknown command */
3282 		break;
3283 	}
3284 
3285 out:
3286 	return error;
3287 }
3288 
3289 #define ENTITLED_RESERVE_ACCESS_ENTITLEMENT \
3290 	"com.apple.private.vfs.entitled-reserve-access"
3291 static int
iopolicysys_vfs_entitled_reserve_access(struct proc * p,int cmd,int scope,int policy,struct _iopol_param_t * iop_param)3292 iopolicysys_vfs_entitled_reserve_access(struct proc *p, int cmd, int scope,
3293     int policy, struct _iopol_param_t *iop_param)
3294 {
3295 	struct uthread *ut;
3296 
3297 	switch (scope) {
3298 	case IOPOL_SCOPE_THREAD:
3299 		ut = get_bsdthread_info(current_thread());
3300 		break;
3301 	case IOPOL_SCOPE_PROCESS:
3302 		ut = NULL;
3303 		break;
3304 	default:
3305 		return EINVAL;
3306 	}
3307 
3308 	if (cmd == IOPOL_CMD_GET) {
3309 		if (scope == IOPOL_SCOPE_THREAD) {
3310 			policy = (os_atomic_load(&ut->uu_flag, relaxed) & UT_FS_ENTITLED_RESERVE_ACCESS) ?
3311 			    IOPOL_VFS_ENTITLED_RESERVE_ACCESS_ON : IOPOL_VFS_ENTITLED_RESERVE_ACCESS_OFF;
3312 		} else {
3313 			policy = (os_atomic_load(&p->p_vfs_iopolicy, relaxed) & P_VFS_IOPOLICY_ENTITLED_RESERVE_ACCESS) ?
3314 			    IOPOL_VFS_ENTITLED_RESERVE_ACCESS_ON : IOPOL_VFS_ENTITLED_RESERVE_ACCESS_OFF;
3315 		}
3316 		iop_param->iop_policy = policy;
3317 		return 0;
3318 	}
3319 
3320 	if (cmd != IOPOL_CMD_SET) {
3321 		return EINVAL;
3322 	}
3323 
3324 	if (!IOCurrentTaskHasEntitlement(ENTITLED_RESERVE_ACCESS_ENTITLEMENT)) {
3325 		return EPERM;
3326 	}
3327 
3328 	switch (policy) {
3329 	case IOPOL_VFS_ENTITLED_RESERVE_ACCESS_OFF:
3330 		if (scope == IOPOL_SCOPE_THREAD) {
3331 			os_atomic_andnot(&ut->uu_flag, UT_FS_ENTITLED_RESERVE_ACCESS, relaxed);
3332 		} else {
3333 			os_atomic_andnot(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_ENTITLED_RESERVE_ACCESS, relaxed);
3334 		}
3335 		break;
3336 	case IOPOL_VFS_ENTITLED_RESERVE_ACCESS_ON:
3337 		if (scope == IOPOL_SCOPE_THREAD) {
3338 			os_atomic_or(&ut->uu_flag, UT_FS_ENTITLED_RESERVE_ACCESS, relaxed);
3339 		} else {
3340 			os_atomic_or(&p->p_vfs_iopolicy, P_VFS_IOPOLICY_ENTITLED_RESERVE_ACCESS, relaxed);
3341 		}
3342 		break;
3343 	default:
3344 		return EINVAL;
3345 	}
3346 
3347 	return 0;
3348 }
3349 
3350 void
proc_apply_task_networkbg(int pid,thread_t thread)3351 proc_apply_task_networkbg(int pid, thread_t thread)
3352 {
3353 	proc_t p = proc_find(pid);
3354 
3355 	if (p != PROC_NULL) {
3356 		do_background_socket(p, thread);
3357 		proc_rele(p);
3358 	}
3359 }
3360 
3361 void
gather_rusage_info(proc_t p,rusage_info_current * ru,int flavor)3362 gather_rusage_info(proc_t p, rusage_info_current *ru, int flavor)
3363 {
3364 	struct rusage_info_child *ri_child;
3365 
3366 	assert(p->p_stats != NULL);
3367 	memset(ru, 0, sizeof(*ru));
3368 	switch (flavor) {
3369 	case RUSAGE_INFO_V6:
3370 		ru->ri_neural_footprint = get_task_neural_nofootprint_total(proc_task(p));
3371 		ru->ri_lifetime_max_neural_footprint = get_task_neural_nofootprint_total_lifetime_max(proc_task(p));
3372 #if CONFIG_LEDGER_INTERVAL_MAX
3373 		ru->ri_interval_max_neural_footprint = get_task_neural_nofootprint_total_interval_max(proc_task(p), FALSE);
3374 #endif
3375 		/* Any P-specific resource counters are captured in fill_task_rusage. */
3376 		OS_FALLTHROUGH;
3377 
3378 	case RUSAGE_INFO_V5:
3379 #if __has_feature(ptrauth_calls)
3380 		if (vm_shared_region_is_reslide(proc_task(p))) {
3381 			ru->ri_flags |= RU_PROC_RUNS_RESLIDE;
3382 		}
3383 #endif /* __has_feature(ptrauth_calls) */
3384 		OS_FALLTHROUGH;
3385 
3386 	case RUSAGE_INFO_V4:
3387 		ru->ri_logical_writes = get_task_logical_writes(proc_task(p), false);
3388 		ru->ri_lifetime_max_phys_footprint = get_task_phys_footprint_lifetime_max(proc_task(p));
3389 #if CONFIG_LEDGER_INTERVAL_MAX
3390 		ru->ri_interval_max_phys_footprint = get_task_phys_footprint_interval_max(proc_task(p), FALSE);
3391 #endif
3392 		OS_FALLTHROUGH;
3393 
3394 	case RUSAGE_INFO_V3:
3395 		fill_task_qos_rusage(proc_task(p), ru);
3396 		fill_task_billed_usage(proc_task(p), ru);
3397 		OS_FALLTHROUGH;
3398 
3399 	case RUSAGE_INFO_V2:
3400 		fill_task_io_rusage(proc_task(p), ru);
3401 		OS_FALLTHROUGH;
3402 
3403 	case RUSAGE_INFO_V1:
3404 		/*
3405 		 * p->p_stats->ri_child statistics are protected under proc lock.
3406 		 */
3407 		proc_lock(p);
3408 
3409 		ri_child = &(p->p_stats->ri_child);
3410 		ru->ri_child_user_time = ri_child->ri_child_user_time;
3411 		ru->ri_child_system_time = ri_child->ri_child_system_time;
3412 		ru->ri_child_pkg_idle_wkups = ri_child->ri_child_pkg_idle_wkups;
3413 		ru->ri_child_interrupt_wkups = ri_child->ri_child_interrupt_wkups;
3414 		ru->ri_child_pageins = ri_child->ri_child_pageins;
3415 		ru->ri_child_elapsed_abstime = ri_child->ri_child_elapsed_abstime;
3416 
3417 		proc_unlock(p);
3418 		OS_FALLTHROUGH;
3419 
3420 	case RUSAGE_INFO_V0:
3421 		proc_getexecutableuuid(p, (unsigned char *)&ru->ri_uuid, sizeof(ru->ri_uuid));
3422 		fill_task_rusage(proc_task(p), ru);
3423 		ru->ri_proc_start_abstime = p->p_stats->ps_start;
3424 	}
3425 }
3426 
3427 int
proc_get_rusage(proc_t p,int flavor,user_addr_t buffer,__unused int is_zombie)3428 proc_get_rusage(proc_t p, int flavor, user_addr_t buffer, __unused int is_zombie)
3429 {
3430 	rusage_info_current ri_current = {};
3431 
3432 	size_t size = 0;
3433 
3434 	switch (flavor) {
3435 	case RUSAGE_INFO_V0:
3436 		size = sizeof(struct rusage_info_v0);
3437 		break;
3438 
3439 	case RUSAGE_INFO_V1:
3440 		size = sizeof(struct rusage_info_v1);
3441 		break;
3442 
3443 	case RUSAGE_INFO_V2:
3444 		size = sizeof(struct rusage_info_v2);
3445 		break;
3446 
3447 	case RUSAGE_INFO_V3:
3448 		size = sizeof(struct rusage_info_v3);
3449 		break;
3450 
3451 	case RUSAGE_INFO_V4:
3452 		size = sizeof(struct rusage_info_v4);
3453 		break;
3454 
3455 	case RUSAGE_INFO_V5:
3456 		size = sizeof(struct rusage_info_v5);
3457 		break;
3458 
3459 	case RUSAGE_INFO_V6:
3460 		size = sizeof(struct rusage_info_v6);
3461 		break;
3462 	default:
3463 		return EINVAL;
3464 	}
3465 
3466 	if (size == 0) {
3467 		return EINVAL;
3468 	}
3469 
3470 	/*
3471 	 * If task is still alive, collect info from the live task itself.
3472 	 * Otherwise, look to the cached info in the zombie proc.
3473 	 */
3474 	if (p->p_ru) {
3475 		return copyout(&p->p_ru->ri, buffer, size);
3476 	} else {
3477 		gather_rusage_info(p, &ri_current, flavor);
3478 		ri_current.ri_proc_exit_abstime = 0;
3479 		return copyout(&ri_current, buffer, size);
3480 	}
3481 }
3482 
3483 static int
mach_to_bsd_rv(int mach_rv)3484 mach_to_bsd_rv(int mach_rv)
3485 {
3486 	int bsd_rv = 0;
3487 
3488 	switch (mach_rv) {
3489 	case KERN_SUCCESS:
3490 		bsd_rv = 0;
3491 		break;
3492 	case KERN_INVALID_ARGUMENT:
3493 		bsd_rv = EINVAL;
3494 		break;
3495 	default:
3496 		panic("unknown error %#x", mach_rv);
3497 	}
3498 
3499 	return bsd_rv;
3500 }
3501 
3502 /*
3503  * Resource limit controls
3504  *
3505  * uap->flavor available flavors:
3506  *
3507  *     RLIMIT_WAKEUPS_MONITOR
3508  *     RLIMIT_CPU_USAGE_MONITOR
3509  *     RLIMIT_THREAD_CPULIMITS
3510  *     RLIMIT_FOOTPRINT_INTERVAL
3511  */
3512 int
proc_rlimit_control(__unused struct proc * p,struct proc_rlimit_control_args * uap,__unused int32_t * retval)3513 proc_rlimit_control(__unused struct proc *p, struct proc_rlimit_control_args *uap, __unused int32_t *retval)
3514 {
3515 	proc_t  targetp;
3516 	int     error = 0;
3517 	uint32_t cpumon_flags;
3518 	uint32_t cpulimits_flags;
3519 	kauth_cred_t my_cred, target_cred;
3520 #if CONFIG_LEDGER_INTERVAL_MAX
3521 	uint32_t footprint_interval_flags;
3522 	uint64_t interval_max_footprint;
3523 #endif /* CONFIG_LEDGER_INTERVAL_MAX */
3524 
3525 	/* -1 implicitly means our own process (perhaps even the current thread for per-thread attributes) */
3526 	if (uap->pid == -1) {
3527 		targetp = proc_self();
3528 	} else {
3529 		targetp = proc_find(uap->pid);
3530 	}
3531 
3532 	/* proc_self() can return NULL for an exiting process */
3533 	if (targetp == PROC_NULL) {
3534 		return ESRCH;
3535 	}
3536 
3537 	my_cred = kauth_cred_get();
3538 	target_cred = kauth_cred_proc_ref(targetp);
3539 
3540 	if (!kauth_cred_issuser(my_cred) && kauth_cred_getruid(my_cred) &&
3541 	    kauth_cred_getuid(my_cred) != kauth_cred_getuid(target_cred) &&
3542 	    kauth_cred_getruid(my_cred) != kauth_cred_getuid(target_cred)) {
3543 		proc_rele(targetp);
3544 		kauth_cred_unref(&target_cred);
3545 		return EACCES;
3546 	}
3547 
3548 	switch (uap->flavor) {
3549 	case RLIMIT_WAKEUPS_MONITOR:
3550 		// Ignore requests silently here, no longer supported.
3551 		error = 0;
3552 		break;
3553 	case RLIMIT_CPU_USAGE_MONITOR:
3554 		cpumon_flags = (uint32_t)uap->arg; // XXX temporarily stashing flags in argp (12592127)
3555 		error = mach_to_bsd_rv(task_cpu_usage_monitor_ctl(proc_task(targetp), &cpumon_flags));
3556 		break;
3557 	case RLIMIT_THREAD_CPULIMITS:
3558 		cpulimits_flags = (uint32_t)uap->arg; // only need a limited set of bits, pass in void * argument
3559 
3560 		if (uap->pid != -1) {
3561 			error = EINVAL;
3562 			break;
3563 		}
3564 
3565 		uint8_t percent = 0;
3566 		uint32_t ms_refill = 0;
3567 		uint64_t ns_refill;
3568 
3569 		percent = (uint8_t)(cpulimits_flags & 0xffU);           /* low 8 bits for percent */
3570 		ms_refill = (cpulimits_flags >> 8) & 0xffffff;          /* next 24 bits represent ms refill value */
3571 		if (percent >= 100 || percent == 0) {
3572 			error = EINVAL;
3573 			break;
3574 		}
3575 
3576 		ns_refill = ((uint64_t)ms_refill) * NSEC_PER_MSEC;
3577 
3578 		error = mach_to_bsd_rv(thread_set_cpulimit(THREAD_CPULIMIT_BLOCK, percent, ns_refill));
3579 		break;
3580 
3581 #if CONFIG_LEDGER_INTERVAL_MAX
3582 	case RLIMIT_FOOTPRINT_INTERVAL:
3583 		footprint_interval_flags = (uint32_t)uap->arg; // XXX temporarily stashing flags in argp (12592127)
3584 		/*
3585 		 * There is currently only one option for this flavor.
3586 		 */
3587 		if ((footprint_interval_flags & FOOTPRINT_INTERVAL_RESET) == 0) {
3588 			error = EINVAL;
3589 			break;
3590 		}
3591 		interval_max_footprint = get_task_phys_footprint_interval_max(proc_task(targetp), TRUE);
3592 		interval_max_footprint = get_task_neural_nofootprint_total_interval_max(proc_task(targetp), TRUE);
3593 		break;
3594 
3595 #endif /* CONFIG_LEDGER_INTERVAL_MAX */
3596 	default:
3597 		error = EINVAL;
3598 		break;
3599 	}
3600 
3601 	proc_rele(targetp);
3602 	kauth_cred_unref(&target_cred);
3603 
3604 	/*
3605 	 * Return value from this function becomes errno to userland caller.
3606 	 */
3607 	return error;
3608 }
3609 
3610 /*
3611  * Return the current amount of CPU consumed by this thread (in either user or kernel mode)
3612  */
3613 int
thread_selfusage(struct proc * p __unused,struct thread_selfusage_args * uap __unused,uint64_t * retval)3614 thread_selfusage(struct proc *p __unused, struct thread_selfusage_args *uap __unused, uint64_t *retval)
3615 {
3616 	uint64_t runtime;
3617 
3618 	runtime = thread_get_runtime_self();
3619 	*retval = runtime;
3620 
3621 	return 0;
3622 }
3623