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