2 * Copyright (c) 2005, 2010 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * process policy syscall implementation
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/proc_internal.h>
39 #include <sys/kauth.h>
40 #include <sys/unistd.h>
42 #include <sys/ioctl.h>
46 #include <security/audit/audit.h>
48 #include <mach/machine.h>
49 #include <mach/mach_types.h>
50 #include <mach/vm_param.h>
51 #include <kern/task.h>
52 #include <kern/lock.h>
53 #include <kern/kalloc.h>
54 #include <kern/assert.h>
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>
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>
69 #include <machine/machine_routines.h>
71 #include <kern/ipc_misc.h>
72 #include <vm/vm_protos.h>
74 static int handle_lowresource(int scope
, int action
, int policy
, int policy_subtype
, user_addr_t attrp
, proc_t proc
, uint64_t target_threadid
);
75 static int handle_resourceuse(int scope
, int action
, int policy
, int policy_subtype
, user_addr_t attrp
, proc_t proc
, uint64_t target_threadid
);
76 static int handle_apptype(int scope
, int action
, int policy
, int policy_subtype
, user_addr_t attrp
, proc_t proc
, uint64_t target_threadid
);
77 static int handle_boost(int scope
, int action
, int policy
, int policy_subtype
, user_addr_t attrp
, proc_t proc
, uint64_t target_threadid
);
79 extern kern_return_t
task_suspend(task_t
);
80 extern kern_return_t
task_resume(task_t
);
83 /***************************** process_policy ********************/
86 *int process_policy(int scope, int action, int policy, int policy_subtype,
87 * proc_policy_attribute_t * attrp, pid_t target_pid,
88 * uint64_t target_threadid)
89 *{ int process_policy(int scope, int action, int policy, int policy_subtype,
90 * user_addr_t attrp, pid_t target_pid, uint64_t target_threadid); }
93 /* system call implementation */
95 process_policy(__unused
struct proc
*p
, struct process_policy_args
* uap
, __unused
int32_t *retval
)
98 int scope
= uap
->scope
;
99 int policy
= uap
->policy
;
100 int action
= uap
->action
;
101 int policy_subtype
= uap
->policy_subtype
;
102 user_addr_t attrp
= uap
->attrp
;
103 pid_t target_pid
= uap
->target_pid
;
104 uint64_t target_threadid
= uap
->target_threadid
;
105 proc_t target_proc
= PROC_NULL
;
106 proc_t curp
= current_proc();
107 kauth_cred_t my_cred
;
109 if ((scope
!= PROC_POLICY_SCOPE_PROCESS
) && (scope
!= PROC_POLICY_SCOPE_THREAD
)) {
113 if (target_pid
== 0 || target_pid
== proc_selfpid())
114 target_proc
= proc_self();
116 target_proc
= proc_find(target_pid
);
118 if (target_proc
== PROC_NULL
)
121 my_cred
= kauth_cred_get();
124 * Resoure starvation control can be used by unpriv resource owner but priv at the time of ownership claim. This is
125 * checked in low resource handle routine. So bypass the checks here.
127 if ((policy
!= PROC_POLICY_RESOURCE_STARVATION
) &&
128 (policy
!= PROC_POLICY_APPTYPE
) &&
129 (!kauth_cred_issuser(my_cred
) && curp
!= p
))
137 case PROC_POLICY_BOOST
:
138 case PROC_POLICY_RESOURCE_USAGE
:
139 /* These policies do their own appropriate mac checks */
142 error
= mac_proc_check_sched(curp
, target_proc
);
146 #endif /* CONFIG_MACF */
149 case PROC_POLICY_BACKGROUND
:
152 case PROC_POLICY_HARDWARE_ACCESS
:
155 case PROC_POLICY_RESOURCE_STARVATION
:
156 error
= handle_lowresource(scope
, action
, policy
, policy_subtype
, attrp
, target_proc
, target_threadid
);
158 case PROC_POLICY_RESOURCE_USAGE
:
159 error
= handle_resourceuse(scope
, action
, policy
, policy_subtype
, attrp
, target_proc
, target_threadid
);
161 case PROC_POLICY_APPTYPE
:
162 error
= handle_apptype(scope
, action
, policy
, policy_subtype
, attrp
, target_proc
, target_threadid
);
164 case PROC_POLICY_BOOST
:
165 error
= handle_boost(scope
, action
, policy
, policy_subtype
, attrp
, target_proc
, target_threadid
);
173 proc_rele(target_proc
);
178 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
)
182 switch(policy_subtype
) {
183 case PROC_POLICY_RS_NONE
:
184 case PROC_POLICY_RS_VIRTUALMEM
:
190 if (action
== PROC_POLICY_ACTION_RESTORE
)
191 error
= proc_resetpcontrol(proc_pid(proc
));
200 handle_resourceuse(__unused
int scope
, __unused
int action
, __unused
int policy
, int policy_subtype
, user_addr_t attrp
, proc_t proc
, __unused
uint64_t target_threadid
)
202 proc_policy_cpuusage_attr_t cpuattr
;
204 proc_t curp
= current_proc();
207 uint64_t interval
= -1ULL;
210 switch(policy_subtype
) {
211 case PROC_POLICY_RUSAGE_NONE
:
212 case PROC_POLICY_RUSAGE_WIREDMEM
:
213 case PROC_POLICY_RUSAGE_VIRTMEM
:
214 case PROC_POLICY_RUSAGE_DISK
:
215 case PROC_POLICY_RUSAGE_NETWORK
:
216 case PROC_POLICY_RUSAGE_POWER
:
221 case PROC_POLICY_RUSAGE_CPU
:
227 /* the cpumon entitlement manages messing with CPU limits on self */
228 error
= mac_proc_check_sched(curp
, proc
);
234 * Allow a process to change CPU usage monitor parameters, unless a MAC policy
235 * overrides it with an entitlement check.
237 entitled
= (mac_proc_check_cpumon(curp
) == 0) ? TRUE
: FALSE
;
243 case PROC_POLICY_ACTION_GET
:
244 error
= proc_get_task_ruse_cpu(proc
->task
, &cpuattr
.ppattr_cpu_attr
,
246 &cpuattr
.ppattr_cpu_attr_interval
,
247 &cpuattr
.ppattr_cpu_attr_deadline
);
249 cpuattr
.ppattr_cpu_percentage
= percentage
;
250 cpuattr
.ppattr_cpu_attr_interval
/= NSEC_PER_SEC
;
251 error
= copyout((proc_policy_cpuusage_attr_t
*)&cpuattr
, (user_addr_t
)attrp
, sizeof(proc_policy_cpuusage_attr_t
));
255 case PROC_POLICY_ACTION_APPLY
:
256 case PROC_POLICY_ACTION_SET
:
257 error
= copyin((user_addr_t
)attrp
, (proc_policy_cpuusage_attr_t
*)&cpuattr
, sizeof(proc_policy_cpuusage_attr_t
));
263 * The process_policy API uses seconds as the units for the interval,
264 * but the mach task policy SPI uses nanoseconds. Do the conversion,
265 * but preserve -1 as it has special meaning.
267 if (cpuattr
.ppattr_cpu_attr_interval
!= -1ULL) {
268 interval
= cpuattr
.ppattr_cpu_attr_interval
* NSEC_PER_SEC
;
273 error
= proc_set_task_ruse_cpu(proc
->task
, cpuattr
.ppattr_cpu_attr
,
274 cpuattr
.ppattr_cpu_percentage
,
276 cpuattr
.ppattr_cpu_attr_deadline
,
280 case PROC_POLICY_ACTION_RESTORE
:
281 error
= proc_clear_task_ruse_cpu(proc
->task
, entitled
);
295 handle_apptype( int scope
,
299 __unused user_addr_t attrp
,
301 __unused
uint64_t target_threadid
)
305 if (scope
!= PROC_POLICY_SCOPE_PROCESS
)
308 /* Temporary compatibility with old importance donation interface until libproc is moved to new boost calls */
309 switch (policy_subtype
) {
310 case PROC_POLICY_IOS_DONATEIMP
:
311 if (action
!= PROC_POLICY_ACTION_ENABLE
)
313 if (target_proc
!= current_proc())
316 /* PROCESS ENABLE APPTYPE DONATEIMP */
317 task_importance_mark_donor(target_proc
->task
, TRUE
);
321 case PROC_POLICY_IOS_HOLDIMP
:
322 if (action
!= PROC_POLICY_ACTION_ENABLE
)
324 if (target_proc
!= current_proc())
327 /* PROCESS ENABLE APPTYPE HOLDIMP */
328 error
= task_importance_hold_external_assertion(current_task(), 1);
332 case PROC_POLICY_IOS_DROPIMP
:
333 if (action
!= PROC_POLICY_ACTION_ENABLE
)
335 if (target_proc
!= current_proc())
338 /* PROCESS ENABLE APPTYPE DROPIMP */
339 error
= task_importance_drop_external_assertion(current_task(), 1);
344 /* continue to TAL handling */
348 if (policy_subtype
!= PROC_POLICY_OSX_APPTYPE_TAL
)
351 /* need to be super user to do this */
352 if (kauth_cred_issuser(kauth_cred_get()) == 0)
355 if (proc_task_is_tal(target_proc
->task
) == FALSE
)
359 case PROC_POLICY_ACTION_ENABLE
:
360 /* PROCESS ENABLE APPTYPE TAL */
361 proc_set_task_policy(target_proc
->task
, THREAD_NULL
,
362 TASK_POLICY_ATTRIBUTE
, TASK_POLICY_TAL
,
365 case PROC_POLICY_ACTION_DISABLE
:
366 /* PROCESS DISABLE APPTYPE TAL */
367 proc_set_task_policy(target_proc
->task
, THREAD_NULL
,
368 TASK_POLICY_ATTRIBUTE
, TASK_POLICY_TAL
,
369 TASK_POLICY_DISABLE
);
380 handle_boost(int scope
,
384 __unused user_addr_t attrp
,
386 __unused
uint64_t target_threadid
)
390 assert(policy
== PROC_POLICY_BOOST
);
392 if (scope
!= PROC_POLICY_SCOPE_PROCESS
)
395 if (target_proc
!= current_proc())
398 switch(policy_subtype
) {
399 case PROC_POLICY_IMP_IMPORTANT
:
400 if (task_is_importance_receiver(target_proc
->task
) == FALSE
)
404 case PROC_POLICY_ACTION_HOLD
:
405 /* PROCESS HOLD BOOST IMPORTANT */
406 error
= task_importance_hold_external_assertion(current_task(), 1);
408 case PROC_POLICY_ACTION_DROP
:
409 /* PROCESS DROP BOOST IMPORTANT */
410 error
= task_importance_drop_external_assertion(current_task(), 1);
418 case PROC_POLICY_IMP_DONATION
:
420 error
= mac_proc_check_sched(current_proc(), target_proc
);
421 if (error
) return error
;
424 case PROC_POLICY_ACTION_SET
:
425 /* PROCESS SET BOOST DONATION */
426 task_importance_mark_donor(target_proc
->task
, TRUE
);
444 * KPI to determine if a pid is currently backgrounded.
445 * Returns ESRCH if pid cannot be found or has started exiting.
446 * Returns EINVAL if state is NULL.
447 * Sets *state to 1 if pid is backgrounded, and 0 otherwise.
450 proc_pidbackgrounded(pid_t pid
, uint32_t* state
)
452 proc_t target_proc
= PROC_NULL
;
457 target_proc
= proc_find(pid
);
459 if (target_proc
== PROC_NULL
)
462 if ( proc_get_effective_task_policy(target_proc
->task
, TASK_POLICY_DARWIN_BG
) ) {
468 proc_rele(target_proc
);
473 proc_apply_resource_actions(void * bsdinfo
, __unused
int type
, int action
)
475 proc_t p
= (proc_t
)bsdinfo
;
478 case PROC_POLICY_RSRCACT_THROTTLE
:
479 /* no need to do anything */
482 case PROC_POLICY_RSRCACT_SUSPEND
:
483 task_suspend(p
->task
);
486 case PROC_POLICY_RSRCACT_TERMINATE
:
490 case PROC_POLICY_RSRCACT_NOTIFY_KQ
:
491 /* not implemented */
494 case PROC_POLICY_RSRCACT_NOTIFY_EXC
:
495 panic("shouldn't be applying exception notification to process!");
504 proc_restore_resource_actions(void * bsdinfo
, __unused
int type
, int action
)
506 proc_t p
= (proc_t
)bsdinfo
;
509 case PROC_POLICY_RSRCACT_THROTTLE
:
510 case PROC_POLICY_RSRCACT_TERMINATE
:
511 case PROC_POLICY_RSRCACT_NOTIFY_KQ
:
512 case PROC_POLICY_RSRCACT_NOTIFY_EXC
:
513 /* no need to do anything */
516 case PROC_POLICY_RSRCACT_SUSPEND
:
517 task_resume(p
->task
);