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
82static int handle_lowresource(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
83static int handle_cpuuse(int action, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
84static int handle_apptype(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
85static int handle_boost(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
86static int handle_no_smt(int scope, int action, proc_t target_proc, uint64_t target_threadid);
87static int handle_tecs(int scope, int action, proc_t target_proc, uint64_t target_threadid);
88
89extern kern_return_t task_suspend(task_t);
90extern kern_return_t task_resume(task_t);
91
92#if !defined(XNU_TARGET_OS_OSX)
93static 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 */
107int
108process_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(pid: 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(cred: 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(proc: curp, proc2: 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, proc: 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, proc: 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, proc: target_proc, target_threadid);
218 break;
219 case PROC_POLICY_BOOST:
220 error = handle_boost(scope, action, policy, policy_subtype, attrp, proc: 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
233out:
234 proc_rele(p: target_proc);
235#if !defined(XNU_TARGET_OS_OSX)
236 kauth_cred_unref(&target_cred);
237#endif
238 return error;
239}
240
241static int
242handle_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(pid: proc_pid(proc));
256 } else {
257 error = EINVAL;
258 }
259
260 return error;
261}
262
263
264static int
265handle_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(cred: kauth_cred_get(), PRIV_PROC_CPUMON_OVERRIDE, flags: 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(proc: curp, proc2: 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(task: proc_task(proc), policyp: &cpuattr.ppattr_cpu_attr,
309 percentagep: &percentage,
310 intervalp: &cpuattr.ppattr_cpu_attr_interval,
311 deadlinep: &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(task: proc_task(proc), policy: (uint16_t)cpuattr.ppattr_cpu_attr,
338 percentage: (uint8_t)MIN(cpuattr.ppattr_cpu_percentage, UINT8_MAX),
339 interval,
340 deadline: cpuattr.ppattr_cpu_attr_deadline,
341 cpumon_entitled: privileged);
342 break;
343
344 /* restore process to prior state */
345 case PROC_POLICY_ACTION_RESTORE:
346 error = proc_clear_task_ruse_cpu(task: proc_task(proc), cpumon_entitled: privileged);
347 break;
348
349 /* re-enable suspended monitor */
350 case PROC_POLICY_ACTION_ENABLE:
351 error = task_resume_cpumon(task: 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)
365static int
366handle_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
437out:
438 return error;
439}
440#endif /* !defined(XNU_TARGET_OS_OSX) */
441
442static int
443handle_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(task: 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(target_task: current_task(), count: 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(target_task: current_task(), count: 1);
495
496 return error;
497
498 default:
499 return EINVAL;
500 }
501}
502
503static int
504handle_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(task: 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(target_task: current_task(), count: 1);
534 break;
535 case PROC_POLICY_ACTION_DROP:
536 /* PROCESS DROP BOOST IMPORTANT */
537 error = task_importance_drop_legacy_external_assertion(target_task: current_task(), count: 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(proc: current_proc(), proc2: 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(task: 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
571static int
572handle_no_smt(int scope, int action, proc_t target_proc, uint64_t target_threadid)
573{
574 extern void task_set_no_smt(task_t);
575
576 if (action != PROC_POLICY_ACTION_APPLY) {
577 return EINVAL;
578 }
579
580 if (scope == PROC_POLICY_SCOPE_PROCESS) {
581 if (target_proc != current_proc()) {
582 return EINVAL;
583 }
584 task_set_no_smt(TASK_NULL);
585 } else if (scope == PROC_POLICY_SCOPE_THREAD) {
586 if (target_threadid != thread_tid(thread: current_thread())) {
587 return EINVAL;
588 }
589 thread_set_no_smt(true);
590 } else {
591 return EINVAL;
592 }
593
594 return 0;
595}
596
597static int
598handle_tecs(int scope, int action, proc_t target_proc, uint64_t target_threadid)
599{
600 if (action != PROC_POLICY_ACTION_APPLY) {
601 return EINVAL;
602 }
603
604 if (scope == PROC_POLICY_SCOPE_PROCESS) {
605 if (target_proc != current_proc()) {
606 return EINVAL;
607 }
608 task_set_tecs(TASK_NULL);
609 } else if (scope == PROC_POLICY_SCOPE_THREAD) {
610 if (target_threadid != thread_tid(thread: current_thread())) {
611 return EINVAL;
612 }
613 if (machine_csv(cve: CPUVN_CI)) {
614 machine_tecs(thr: current_thread());
615 }
616 } else {
617 return EINVAL;
618 }
619
620 return 0;
621}
622
623/*
624 * KPI to determine if a pid is currently backgrounded.
625 * Returns ESRCH if pid cannot be found or has started exiting.
626 * Returns EINVAL if state is NULL.
627 * Sets *state to 1 if pid is backgrounded, and 0 otherwise.
628 */
629int
630proc_pidbackgrounded(pid_t pid, uint32_t* state)
631{
632 proc_t target_proc = PROC_NULL;
633
634 if (state == NULL) {
635 return EINVAL;
636 }
637
638 target_proc = proc_find(pid);
639
640 if (target_proc == PROC_NULL) {
641 return ESRCH;
642 }
643
644 if (proc_get_effective_task_policy(task: proc_task(target_proc), TASK_POLICY_DARWIN_BG)) {
645 *state = 1;
646 } else {
647 *state = 0;
648 }
649
650 proc_rele(p: target_proc);
651 return 0;
652}
653
654/*
655 * Get the darwin background state of the originator. If the current
656 * process app type is App, then it is the originator, else if it is
657 * a Daemon, then creator of the Resource Accounting attribute of
658 * the current thread voucher is the originator of the work.
659 */
660int
661proc_get_originatorbgstate(uint32_t *is_backgrounded)
662{
663 uint32_t bgstate;
664 proc_t p = current_proc();
665 uint32_t flagsp = 0;
666 kern_return_t kr;
667 pid_t pid;
668 int ret;
669 thread_t thread = current_thread();
670
671 bgstate = proc_get_effective_thread_policy(thread, TASK_POLICY_DARWIN_BG);
672
673 /* If current thread or task backgrounded, return background */
674 if (bgstate) {
675 *is_backgrounded = 1;
676 return 0;
677 }
678
679 /* Check if current process app type is App, then return foreground */
680 proc_get_darwinbgstate(task: proc_task(p), flagsp: &flagsp);
681 if ((flagsp & PROC_FLAG_APPLICATION) == PROC_FLAG_APPLICATION) {
682 *is_backgrounded = 0;
683 return 0;
684 }
685
686 /*
687 * Get the current voucher origin pid and it's bgstate.The pid
688 * returned here might not be valid or may have been recycled.
689 */
690 kr = thread_get_current_voucher_origin_pid(pid: &pid);
691 if (kr != KERN_SUCCESS) {
692 if (kr == KERN_INVALID_TASK) {
693 return ESRCH;
694 } else if (kr == KERN_INVALID_VALUE) {
695 return ENOATTR;
696 } else {
697 return EINVAL;
698 }
699 }
700
701 ret = proc_pidbackgrounded(pid, state: is_backgrounded);
702 return ret;
703}
704
705int
706proc_apply_resource_actions(void * bsdinfo, __unused int type, int action)
707{
708 proc_t p = (proc_t)bsdinfo;
709
710 switch (action) {
711 case PROC_POLICY_RSRCACT_THROTTLE:
712 /* no need to do anything */
713 break;
714
715 case PROC_POLICY_RSRCACT_SUSPEND:
716 task_suspend(proc_task(p));
717 break;
718
719 case PROC_POLICY_RSRCACT_TERMINATE:
720 psignal(p, SIGKILL);
721 break;
722
723 case PROC_POLICY_RSRCACT_NOTIFY_KQ:
724 /* not implemented */
725 break;
726
727 case PROC_POLICY_RSRCACT_NOTIFY_EXC:
728 panic("shouldn't be applying exception notification to process!");
729 break;
730 }
731
732 return 0;
733}
734
735int
736proc_restore_resource_actions(void * bsdinfo, __unused int type, int action)
737{
738 proc_t p = (proc_t)bsdinfo;
739
740 switch (action) {
741 case PROC_POLICY_RSRCACT_THROTTLE:
742 case PROC_POLICY_RSRCACT_TERMINATE:
743 case PROC_POLICY_RSRCACT_NOTIFY_KQ:
744 case PROC_POLICY_RSRCACT_NOTIFY_EXC:
745 /* no need to do anything */
746 break;
747
748 case PROC_POLICY_RSRCACT_SUSPEND:
749 task_resume(proc_task(p));
750 break;
751 }
752
753 return 0;
754}
755