xref: /xnu-12377.41.6/bsd/kern/process_policy.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1 /*
2  * Copyright (c) 2005-2016 Apple Computer, 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 
29 /*
30  * process policy syscall implementation
31  */
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/priv.h>
38 #include <sys/proc_internal.h>
39 #include <sys/proc.h>
40 #include <sys/kauth.h>
41 #include <sys/unistd.h>
42 #include <sys/buf.h>
43 #include <sys/ioctl.h>
44 #include <sys/vm.h>
45 #include <sys/user.h>
46 
47 #include <mach/machine.h>
48 #include <mach/mach_types.h>
49 #include <mach/vm_param.h>
50 #include <kern/task.h>
51 #include <kern/assert.h>
52 #include <kern/policy_internal.h>
53 
54 #include <vm/vm_kern.h>
55 #include <vm/vm_map.h>
56 #include <mach/host_info.h>
57 #include <mach/task_info.h>
58 #include <mach/thread_info.h>
59 #include <mach/vm_region.h>
60 
61 #include <sys/process_policy.h>
62 #include <sys/proc_info.h>
63 #include <sys/bsdtask_info.h>
64 #include <sys/kdebug.h>
65 #include <sys/sysproto.h>
66 #include <sys/msgbuf.h>
67 
68 #include <machine/machine_routines.h>
69 
70 #include <kern/ipc_misc.h>
71 #include <vm/vm_protos.h>
72 
73 #if !defined(XNU_TARGET_OS_OSX)
74 #include <sys/kern_memorystatus.h>
75 #endif /* !defined(XNU_TARGET_OS_OSX) */
76 
77 #if CONFIG_MACF
78 #include <security/mac.h>
79 #include <security/mac_framework.h>
80 #endif /* CONFIG_MACF */
81 
82 static int handle_lowresource(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
83 static int handle_cpuuse(int action, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
84 static int handle_apptype(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
85 static int handle_boost(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
86 static int handle_no_smt(int scope, int action, proc_t target_proc, uint64_t target_threadid);
87 static int handle_tecs(int scope, int action, proc_t target_proc, uint64_t target_threadid);
88 
89 extern kern_return_t task_suspend(task_t);
90 extern kern_return_t task_resume(task_t);
91 
92 #if !defined(XNU_TARGET_OS_OSX)
93 static int handle_applifecycle(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
94 #endif /* !defined(XNU_TARGET_OS_OSX) */
95 
96 /***************************** process_policy ********************/
97 
98 /*
99  * int process_policy(int scope, int action, int policy, int policy_subtype,
100  *                   proc_policy_attribute_t * attrp, pid_t target_pid,
101  *                   uint64_t target_threadid)
102  *{ int process_policy(int scope, int action, int policy, int policy_subtype,
103  * user_addr_t attrp, pid_t target_pid, uint64_t target_threadid); }
104  */
105 
106 /* system call implementation */
107 int
process_policy(__unused struct proc * p,struct process_policy_args * uap,__unused int32_t * retval)108 process_policy(__unused struct proc *p, struct process_policy_args * uap, __unused int32_t *retval)
109 {
110 	int error = 0;
111 	int scope = uap->scope;
112 	int policy = uap->policy;
113 	int action = uap->action;
114 	int policy_subtype = uap->policy_subtype;
115 	user_addr_t attrp = uap->attrp;
116 	pid_t target_pid = uap->target_pid;
117 	uint64_t target_threadid = uap->target_threadid;
118 	proc_t target_proc = PROC_NULL;
119 #if CONFIG_MACF || defined(XNU_TARGET_OS_OSX)
120 	proc_t curp = current_proc();
121 #endif
122 	kauth_cred_t my_cred;
123 #if !defined(XNU_TARGET_OS_OSX)
124 	kauth_cred_t target_cred;
125 #endif
126 
127 	if ((scope != PROC_POLICY_SCOPE_PROCESS) && (scope != PROC_POLICY_SCOPE_THREAD)) {
128 		return EINVAL;
129 	}
130 
131 	if (target_pid == 0 || target_pid == proc_selfpid()) {
132 		target_proc = proc_self();
133 	} else {
134 		target_proc = proc_find(target_pid);
135 	}
136 
137 	if (target_proc == PROC_NULL) {
138 		return ESRCH;
139 	}
140 
141 	my_cred = kauth_cred_get();
142 
143 #if !defined(XNU_TARGET_OS_OSX)
144 	target_cred = kauth_cred_proc_ref(target_proc);
145 
146 	if (!kauth_cred_issuser(my_cred) && kauth_cred_getruid(my_cred) &&
147 	    kauth_cred_getuid(my_cred) != kauth_cred_getuid(target_cred) &&
148 	    kauth_cred_getruid(my_cred) != kauth_cred_getuid(target_cred))
149 #else
150 	/*
151 	 * Resoure starvation control can be used by unpriv resource owner but priv at the time of ownership claim. This is
152 	 * checked in low resource handle routine. So bypass the checks here.
153 	 */
154 	if ((policy != PROC_POLICY_RESOURCE_STARVATION) &&
155 	    (policy != PROC_POLICY_APPTYPE) &&
156 	    (!kauth_cred_issuser(my_cred) && curp != target_proc))
157 #endif
158 	{
159 		error = EPERM;
160 		goto out;
161 	}
162 
163 #if CONFIG_MACF
164 	switch (policy) {
165 	case PROC_POLICY_BOOST:
166 	case PROC_POLICY_RESOURCE_USAGE:
167 #if !defined(XNU_TARGET_OS_OSX)
168 	case PROC_POLICY_APPTYPE:
169 	case PROC_POLICY_APP_LIFECYCLE:
170 #endif
171 		/* These policies do their own appropriate mac checks */
172 		break;
173 	default:
174 		error = mac_proc_check_sched(curp, target_proc);
175 		if (error) {
176 			goto out;
177 		}
178 		break;
179 	}
180 #endif /* CONFIG_MACF */
181 
182 	switch (policy) {
183 	case PROC_POLICY_BACKGROUND:
184 		error = ENOTSUP;
185 		break;
186 	case PROC_POLICY_HARDWARE_ACCESS:
187 		error = ENOTSUP;
188 		break;
189 	case PROC_POLICY_RESOURCE_STARVATION:
190 		error = handle_lowresource(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
191 		break;
192 	case PROC_POLICY_RESOURCE_USAGE:
193 		switch (policy_subtype) {
194 		case PROC_POLICY_RUSAGE_NONE:
195 		case PROC_POLICY_RUSAGE_WIREDMEM:
196 		case PROC_POLICY_RUSAGE_VIRTMEM:
197 		case PROC_POLICY_RUSAGE_DISK:
198 		case PROC_POLICY_RUSAGE_NETWORK:
199 		case PROC_POLICY_RUSAGE_POWER:
200 			error = ENOTSUP;
201 			goto out;
202 		default:
203 			error = EINVAL;
204 			goto out;
205 		case PROC_POLICY_RUSAGE_CPU:
206 			break;
207 		}
208 
209 		error = handle_cpuuse(action, attrp, target_proc, target_threadid);
210 		break;
211 #if !defined(XNU_TARGET_OS_OSX)
212 	case PROC_POLICY_APP_LIFECYCLE:
213 		error = handle_applifecycle(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
214 		break;
215 #endif /* !defined(XNU_TARGET_OS_OSX) */
216 	case PROC_POLICY_APPTYPE:
217 		error = handle_apptype(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
218 		break;
219 	case PROC_POLICY_BOOST:
220 		error = handle_boost(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
221 		break;
222 	case PROC_POLICY_NO_SMT:
223 		error = handle_no_smt(scope, action, target_proc, target_threadid);
224 		break;
225 	case PROC_POLICY_TECS:
226 		error = handle_tecs(scope, action, target_proc, target_threadid);
227 		break;
228 	default:
229 		error = EINVAL;
230 		break;
231 	}
232 
233 out:
234 	proc_rele(target_proc);
235 #if !defined(XNU_TARGET_OS_OSX)
236 	kauth_cred_unref(&target_cred);
237 #endif
238 	return error;
239 }
240 
241 static int
handle_lowresource(__unused int scope,int action,__unused int policy,int policy_subtype,__unused user_addr_t attrp,proc_t proc,__unused uint64_t target_threadid)242 handle_lowresource(__unused int scope, int action, __unused int policy, int policy_subtype, __unused user_addr_t attrp, proc_t proc, __unused uint64_t target_threadid)
243 {
244 	int error = 0;
245 
246 	switch (policy_subtype) {
247 	case PROC_POLICY_RS_NONE:
248 	case PROC_POLICY_RS_VIRTUALMEM:
249 		break;
250 	default:
251 		return EINVAL;
252 	}
253 
254 	if (action == PROC_POLICY_ACTION_RESTORE) {
255 		error = proc_resetpcontrol(proc_pid(proc));
256 	} else {
257 		error = EINVAL;
258 	}
259 
260 	return error;
261 }
262 
263 
264 static int
handle_cpuuse(int action,user_addr_t attrp,proc_t proc,__unused uint64_t target_threadid)265 handle_cpuuse(int action, user_addr_t attrp, proc_t proc, __unused uint64_t target_threadid)
266 {
267 	proc_policy_cpuusage_attr_t     cpuattr = { };
268 #if CONFIG_MACF || defined(XNU_TARGET_OS_OSX)
269 	proc_t                          curp = current_proc();
270 #endif
271 	Boolean                         privileged = FALSE;
272 	Boolean                         canEnable = FALSE;
273 	uint64_t                        interval = -1ULL;
274 	int                             error = 0;
275 	uint8_t                         percentage;
276 
277 #if defined(XNU_TARGET_OS_OSX)
278 	/* On macOS, tasks can only set and clear their own CPU limits. */
279 	if ((action == PROC_POLICY_ACTION_APPLY || action == PROC_POLICY_ACTION_RESTORE)
280 	    && curp != proc) {
281 		return EPERM;
282 	}
283 	/* No privilege required on macOS. */
284 	privileged = TRUE;
285 #endif
286 
287 #if CONFIG_MACF
288 	/* Is caller privileged to set less-restrictive scheduling parameters? */
289 	if (!privileged) {
290 		privileged = (priv_check_cred(kauth_cred_get(), PRIV_PROC_CPUMON_OVERRIDE, 0) == 0);
291 	}
292 	canEnable = (privileged && action == PROC_POLICY_ACTION_ENABLE);
293 
294 	if (!canEnable && curp != proc) {
295 		/*
296 		 * Can the current process change scheduling parameters for
297 		 * the target process?
298 		 */
299 		error = mac_proc_check_sched(curp, proc);
300 		if (error) {
301 			return error;
302 		}
303 	}
304 #endif
305 
306 	switch (action) {
307 	case PROC_POLICY_ACTION_GET:
308 		error = proc_get_task_ruse_cpu(proc_task(proc), &cpuattr.ppattr_cpu_attr,
309 		    &percentage,
310 		    &cpuattr.ppattr_cpu_attr_interval,
311 		    &cpuattr.ppattr_cpu_attr_deadline);
312 		if (error == 0) {
313 			cpuattr.ppattr_cpu_percentage = percentage;
314 			cpuattr.ppattr_cpu_attr_interval /= NSEC_PER_SEC;
315 			error = copyout((proc_policy_cpuusage_attr_t *)&cpuattr, (user_addr_t)attrp, sizeof(proc_policy_cpuusage_attr_t));
316 		}
317 		break;
318 
319 	case PROC_POLICY_ACTION_APPLY:
320 	case PROC_POLICY_ACTION_SET:
321 		error = copyin((user_addr_t)attrp, (proc_policy_cpuusage_attr_t *)&cpuattr, sizeof(proc_policy_cpuusage_attr_t));
322 		if (error != 0) {
323 			return error;
324 		}
325 
326 		/*
327 		 * The process_policy API uses seconds as the units for the interval,
328 		 * but the mach task policy SPI uses nanoseconds. Do the conversion,
329 		 * but preserve -1 as it has special meaning.
330 		 */
331 		if (cpuattr.ppattr_cpu_attr_interval != -1ULL) {
332 			interval = cpuattr.ppattr_cpu_attr_interval * NSEC_PER_SEC;
333 		} else {
334 			interval = -1ULL;
335 		}
336 
337 		error = proc_set_task_ruse_cpu(proc_task(proc), (uint16_t)cpuattr.ppattr_cpu_attr,
338 		    (uint8_t)MIN(cpuattr.ppattr_cpu_percentage, UINT8_MAX),
339 		    interval,
340 		    cpuattr.ppattr_cpu_attr_deadline,
341 		    privileged);
342 		break;
343 
344 	/* restore process to prior state */
345 	case PROC_POLICY_ACTION_RESTORE:
346 		error = proc_clear_task_ruse_cpu(proc_task(proc), privileged);
347 		break;
348 
349 	/* re-enable suspended monitor */
350 	case PROC_POLICY_ACTION_ENABLE:
351 		error = task_resume_cpumon(proc_task(proc));
352 		break;
353 
354 	case PROC_POLICY_ACTION_REMOVE:
355 
356 	default:
357 		error = EINVAL;
358 		break;
359 	}
360 
361 	return error;
362 }
363 
364 #if !defined(XNU_TARGET_OS_OSX)
365 static int
handle_applifecycle(__unused int scope,int action,__unused int policy,int policy_subtype,user_addr_t attrp,proc_t proc,__unused uint64_t target_threadid)366 handle_applifecycle(__unused int scope,
367     int action,
368     __unused int policy,
369     int policy_subtype,
370     user_addr_t attrp,
371     proc_t proc,
372     __unused uint64_t target_threadid)
373 {
374 	int error = 0;
375 	int state = 0;
376 
377 	switch (policy_subtype) {
378 	case PROC_POLICY_APPLIFE_NONE:
379 		error = 0;
380 		break;
381 
382 	case PROC_POLICY_APPLIFE_STATE:
383 		/* appstate is no longer supported */
384 		error = ENOTSUP;
385 		break;
386 
387 	case PROC_POLICY_APPLIFE_DEVSTATUS:
388 #if CONFIG_MACF
389 		/* ToDo - this should be a generic check, since we could potentially hang other behaviours here. */
390 		error = mac_proc_check_suspend_resume(proc, MAC_PROC_CHECK_HIBERNATE);
391 		if (error) {
392 			error = EPERM;
393 			goto out;
394 		}
395 #endif
396 #if CONFIG_MEMORYSTATUS
397 		if (action == PROC_POLICY_ACTION_APPLY) {
398 			/* Used as a freeze hint */
399 			memorystatus_on_inactivity(proc);
400 
401 			/* in future use devicestatus for pid_socketshutdown() */
402 			error = 0;
403 		} else
404 #endif
405 		{
406 			error = EINVAL;
407 		}
408 		break;
409 
410 	case PROC_POLICY_APPLIFE_PIDBIND:
411 #if CONFIG_MACF
412 		error = mac_proc_check_suspend_resume(proc, MAC_PROC_CHECK_PIDBIND);
413 		if (error) {
414 			error = EPERM;
415 			goto out;
416 		}
417 #endif
418 		error = copyin((user_addr_t)attrp, (int  *)&state, sizeof(int));
419 		if (error != 0) {
420 			goto out;
421 		}
422 #if CONFIG_TASKWATCH
423 		if (action == PROC_POLICY_ACTION_APPLY) {
424 			/* bind the thread in target_thread in current process to target_proc */
425 			error = proc_lf_pidbind(current_task(), target_threadid, proc_task(proc), state);
426 		} else
427 #endif /* CONFIG_TASKWATCH */
428 		{
429 			error = EINVAL;
430 		}
431 		break;
432 	default:
433 		error = EINVAL;
434 		break;
435 	}
436 
437 out:
438 	return error;
439 }
440 #endif /* !defined(XNU_TARGET_OS_OSX) */
441 
442 static int
handle_apptype(int scope,int action,__unused int policy,int policy_subtype,__unused user_addr_t attrp,proc_t target_proc,__unused uint64_t target_threadid)443 handle_apptype(         int scope,
444     int action,
445     __unused int policy,
446     int policy_subtype,
447     __unused user_addr_t attrp,
448     proc_t target_proc,
449     __unused uint64_t target_threadid)
450 {
451 	int error = 0;
452 
453 	if (scope != PROC_POLICY_SCOPE_PROCESS) {
454 		return EINVAL;
455 	}
456 
457 	/* Temporary compatibility with old importance donation interface until libproc is moved to new boost calls */
458 	switch (policy_subtype) {
459 	case PROC_POLICY_IOS_DONATEIMP:
460 		if (action != PROC_POLICY_ACTION_ENABLE) {
461 			return EINVAL;
462 		}
463 		if (target_proc != current_proc()) {
464 			return EINVAL;
465 		}
466 
467 		/* PROCESS ENABLE APPTYPE DONATEIMP */
468 		task_importance_mark_donor(proc_task(target_proc), TRUE);
469 
470 		return 0;
471 
472 	case PROC_POLICY_IOS_HOLDIMP:
473 		if (action != PROC_POLICY_ACTION_ENABLE) {
474 			return EINVAL;
475 		}
476 		if (target_proc != current_proc()) {
477 			return EINVAL;
478 		}
479 
480 		/* PROCESS ENABLE APPTYPE HOLDIMP */
481 		error = task_importance_hold_legacy_external_assertion(current_task(), 1);
482 
483 		return error;
484 
485 	case PROC_POLICY_IOS_DROPIMP:
486 		if (action != PROC_POLICY_ACTION_ENABLE) {
487 			return EINVAL;
488 		}
489 		if (target_proc != current_proc()) {
490 			return EINVAL;
491 		}
492 
493 		/* PROCESS ENABLE APPTYPE DROPIMP */
494 		error = task_importance_drop_legacy_external_assertion(current_task(), 1);
495 
496 		return error;
497 
498 	default:
499 		return EINVAL;
500 	}
501 }
502 
503 static int
handle_boost(int scope,int action,__unused int policy,int policy_subtype,__unused user_addr_t attrp,proc_t target_proc,__unused uint64_t target_threadid)504 handle_boost(int scope,
505     int action,
506     __unused int policy,
507     int policy_subtype,
508     __unused user_addr_t attrp,
509     proc_t target_proc,
510     __unused uint64_t target_threadid)
511 {
512 	int error = 0;
513 
514 	assert(policy == PROC_POLICY_BOOST);
515 
516 	if (scope != PROC_POLICY_SCOPE_PROCESS) {
517 		return EINVAL;
518 	}
519 
520 	if (target_proc != current_proc()) {
521 		return EINVAL;
522 	}
523 
524 	switch (policy_subtype) {
525 	case PROC_POLICY_IMP_IMPORTANT:
526 		if (task_is_importance_receiver_type(proc_task(target_proc)) == FALSE) {
527 			return EINVAL;
528 		}
529 
530 		switch (action) {
531 		case PROC_POLICY_ACTION_HOLD:
532 			/* PROCESS HOLD BOOST IMPORTANT */
533 			error = task_importance_hold_legacy_external_assertion(current_task(), 1);
534 			break;
535 		case PROC_POLICY_ACTION_DROP:
536 			/* PROCESS DROP BOOST IMPORTANT */
537 			error = task_importance_drop_legacy_external_assertion(current_task(), 1);
538 			break;
539 		default:
540 			error = (EINVAL);
541 			break;
542 		}
543 		break;
544 
545 	case PROC_POLICY_IMP_DONATION:
546 #if CONFIG_MACF
547 		error = mac_proc_check_sched(current_proc(), target_proc);
548 		if (error) {
549 			return error;
550 		}
551 #endif
552 		switch (action) {
553 		case PROC_POLICY_ACTION_SET:
554 			/* PROCESS SET BOOST DONATION */
555 			task_importance_mark_donor(proc_task(target_proc), TRUE);
556 			break;
557 		default:
558 			error = (EINVAL);
559 			break;
560 		}
561 		break;
562 
563 	default:
564 		error = (EINVAL);
565 		break;
566 	}
567 
568 	return error;
569 }
570 
571 #if CONFIG_SCHED_SMT
572 static int
handle_no_smt(int scope,int action,proc_t target_proc,uint64_t target_threadid)573 handle_no_smt(int scope, int action, proc_t target_proc, uint64_t target_threadid)
574 {
575 	extern void task_set_no_smt(task_t);
576 
577 	if (action != PROC_POLICY_ACTION_APPLY) {
578 		return EINVAL;
579 	}
580 
581 	if (scope == PROC_POLICY_SCOPE_PROCESS) {
582 		if (target_proc != current_proc()) {
583 			return EINVAL;
584 		}
585 		task_set_no_smt(TASK_NULL);
586 	} else if (scope == PROC_POLICY_SCOPE_THREAD) {
587 		if (target_threadid != thread_tid(current_thread())) {
588 			return EINVAL;
589 		}
590 		thread_set_no_smt(true);
591 	} else {
592 		return EINVAL;
593 	}
594 	return 0;
595 }
596 #else /* CONFIG_SCHED_SMT */
597 static int
handle_no_smt(__unused int scope,__unused int action,__unused proc_t target_proc,__unused uint64_t target_threadid)598 handle_no_smt(__unused int scope, __unused int action, __unused proc_t target_proc, __unused uint64_t target_threadid)
599 {
600 	return 0;
601 }
602 #endif /* CONFIG_SCHED_SMT */
603 
604 static int
handle_tecs(int scope,int action,proc_t target_proc,uint64_t target_threadid)605 handle_tecs(int scope, int action, proc_t target_proc, uint64_t target_threadid)
606 {
607 	if (action != PROC_POLICY_ACTION_APPLY) {
608 		return EINVAL;
609 	}
610 
611 	if (scope == PROC_POLICY_SCOPE_PROCESS) {
612 		if (target_proc != current_proc()) {
613 			return EINVAL;
614 		}
615 		task_set_tecs(TASK_NULL);
616 	} else if (scope == PROC_POLICY_SCOPE_THREAD) {
617 		if (target_threadid != thread_tid(current_thread())) {
618 			return EINVAL;
619 		}
620 		if (machine_csv(CPUVN_CI)) {
621 			machine_tecs(current_thread());
622 		}
623 	} else {
624 		return EINVAL;
625 	}
626 
627 	return 0;
628 }
629 
630 /*
631  * KPI to determine if a pid is currently backgrounded.
632  * Returns ESRCH if pid cannot be found or has started exiting.
633  * Returns EINVAL if state is NULL.
634  * Sets *state to 1 if pid is backgrounded, and 0 otherwise.
635  */
636 int
proc_pidbackgrounded(pid_t pid,uint32_t * state)637 proc_pidbackgrounded(pid_t pid, uint32_t* state)
638 {
639 	proc_t target_proc = PROC_NULL;
640 
641 	if (state == NULL) {
642 		return EINVAL;
643 	}
644 
645 	target_proc = proc_find(pid);
646 
647 	if (target_proc == PROC_NULL) {
648 		return ESRCH;
649 	}
650 
651 	if (proc_get_effective_task_policy(proc_task(target_proc), TASK_POLICY_DARWIN_BG)) {
652 		*state = 1;
653 	} else {
654 		*state = 0;
655 	}
656 
657 	proc_rele(target_proc);
658 	return 0;
659 }
660 
661 /*
662  * Get the darwin background state of the originator. If the current
663  * process app type is App, then it is the originator, else if it is
664  * a Daemon, then creator of the Resource Accounting attribute of
665  * the current thread voucher is the originator of the work.
666  */
667 int
proc_get_originatorbgstate(uint32_t * is_backgrounded)668 proc_get_originatorbgstate(uint32_t *is_backgrounded)
669 {
670 	uint32_t bgstate;
671 	proc_t p = current_proc();
672 	uint32_t flagsp = 0;
673 	kern_return_t kr;
674 	pid_t pid;
675 	int ret;
676 	thread_t thread = current_thread();
677 
678 	bgstate = proc_get_effective_thread_policy(thread, TASK_POLICY_DARWIN_BG);
679 
680 	/* If current thread or task backgrounded, return background */
681 	if (bgstate) {
682 		*is_backgrounded = 1;
683 		return 0;
684 	}
685 
686 	/* Check if current process app type is App, then return foreground */
687 	proc_get_darwinbgstate(proc_task(p), &flagsp);
688 	if ((flagsp & PROC_FLAG_APPLICATION) == PROC_FLAG_APPLICATION) {
689 		*is_backgrounded = 0;
690 		return 0;
691 	}
692 
693 	/*
694 	 * Get the current voucher origin pid and it's bgstate.The pid
695 	 * returned here might not be valid or may have been recycled.
696 	 */
697 	kr = thread_get_current_voucher_origin_pid(&pid);
698 	if (kr != KERN_SUCCESS) {
699 		if (kr == KERN_INVALID_TASK) {
700 			return ESRCH;
701 		} else if (kr == KERN_INVALID_VALUE) {
702 			return ENOATTR;
703 		} else {
704 			return EINVAL;
705 		}
706 	}
707 
708 	ret = proc_pidbackgrounded(pid, is_backgrounded);
709 	return ret;
710 }
711 
712 int
proc_apply_resource_actions(void * bsdinfo,__unused int type,int action)713 proc_apply_resource_actions(void * bsdinfo, __unused int type, int action)
714 {
715 	proc_t p = (proc_t)bsdinfo;
716 
717 	switch (action) {
718 	case PROC_POLICY_RSRCACT_THROTTLE:
719 		/* no need to do anything */
720 		break;
721 
722 	case PROC_POLICY_RSRCACT_SUSPEND:
723 		task_suspend(proc_task(p));
724 		break;
725 
726 	case PROC_POLICY_RSRCACT_TERMINATE:
727 		psignal(p, SIGKILL);
728 		break;
729 
730 	case PROC_POLICY_RSRCACT_NOTIFY_KQ:
731 		/* not implemented */
732 		break;
733 
734 	case PROC_POLICY_RSRCACT_NOTIFY_EXC:
735 		panic("shouldn't be applying exception notification to process!");
736 		break;
737 	}
738 
739 	return 0;
740 }
741 
742 int
proc_restore_resource_actions(void * bsdinfo,__unused int type,int action)743 proc_restore_resource_actions(void * bsdinfo, __unused int type, int action)
744 {
745 	proc_t p = (proc_t)bsdinfo;
746 
747 	switch (action) {
748 	case PROC_POLICY_RSRCACT_THROTTLE:
749 	case PROC_POLICY_RSRCACT_TERMINATE:
750 	case PROC_POLICY_RSRCACT_NOTIFY_KQ:
751 	case PROC_POLICY_RSRCACT_NOTIFY_EXC:
752 		/* no need to do anything */
753 		break;
754 
755 	case PROC_POLICY_RSRCACT_SUSPEND:
756 		task_resume(proc_task(p));
757 		break;
758 	}
759 
760 	return 0;
761 }
762