]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/process_policy.c
xnu-2422.110.17.tar.gz
[apple/xnu.git] / bsd / kern / process_policy.c
CommitLineData
6d2010ae
A
1/*
2 * Copyright (c) 2005, 2010 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/proc_internal.h>
39236c6e 38#include <sys/proc.h>
6d2010ae
A
39#include <sys/kauth.h>
40#include <sys/unistd.h>
41#include <sys/buf.h>
42#include <sys/ioctl.h>
43#include <sys/vm.h>
44#include <sys/user.h>
45
46#include <security/audit/audit.h>
47
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>
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
A
73
74static int handle_lowresource(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
6d2010ae
A
75static int handle_resourceuse(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
76static int handle_apptype(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
39236c6e 77static 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
78
79extern kern_return_t task_suspend(task_t);
80extern kern_return_t task_resume(task_t);
81
316670eb 82
6d2010ae
A
83/***************************** process_policy ********************/
84
85/*
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); }
91 */
92
39236c6e 93/* system call implementation */
6d2010ae 94int
316670eb 95process_policy(__unused struct proc *p, struct process_policy_args * uap, __unused int32_t *retval)
6d2010ae
A
96{
97 int error = 0;
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;
316670eb 105 proc_t target_proc = PROC_NULL;
6d2010ae
A
106 proc_t curp = current_proc();
107 kauth_cred_t my_cred;
6d2010ae
A
108
109 if ((scope != PROC_POLICY_SCOPE_PROCESS) && (scope != PROC_POLICY_SCOPE_THREAD)) {
110 return(EINVAL);
111 }
39236c6e
A
112
113 if (target_pid == 0 || target_pid == proc_selfpid())
114 target_proc = proc_self();
115 else
116 target_proc = proc_find(target_pid);
117
118 if (target_proc == PROC_NULL)
316670eb 119 return(ESRCH);
6d2010ae 120
316670eb 121 my_cred = kauth_cred_get();
6d2010ae 122
6d2010ae
A
123 /*
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.
126 */
127 if ((policy != PROC_POLICY_RESOURCE_STARVATION) &&
128 (policy != PROC_POLICY_APPTYPE) &&
316670eb 129 (!kauth_cred_issuser(my_cred) && curp != p))
6d2010ae
A
130 {
131 error = EPERM;
132 goto out;
133 }
134
135#if CONFIG_MACF
39236c6e
A
136 switch (policy) {
137 case PROC_POLICY_BOOST:
138 case PROC_POLICY_RESOURCE_USAGE:
139 /* These policies do their own appropriate mac checks */
140 break;
141 default:
142 error = mac_proc_check_sched(curp, target_proc);
143 if (error) goto out;
144 break;
316670eb 145 }
316670eb 146#endif /* CONFIG_MACF */
6d2010ae 147
6d2010ae
A
148 switch(policy) {
149 case PROC_POLICY_BACKGROUND:
39236c6e 150 error = ENOTSUP;
6d2010ae
A
151 break;
152 case PROC_POLICY_HARDWARE_ACCESS:
39236c6e 153 error = ENOTSUP;
6d2010ae
A
154 break;
155 case PROC_POLICY_RESOURCE_STARVATION:
39236c6e 156 error = handle_lowresource(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
6d2010ae
A
157 break;
158 case PROC_POLICY_RESOURCE_USAGE:
316670eb
A
159 error = handle_resourceuse(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
160 break;
6d2010ae 161 case PROC_POLICY_APPTYPE:
316670eb 162 error = handle_apptype(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
6d2010ae 163 break;
39236c6e
A
164 case PROC_POLICY_BOOST:
165 error = handle_boost(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
166 break;
6d2010ae
A
167 default:
168 error = EINVAL;
169 break;
170 }
171
172out:
316670eb 173 proc_rele(target_proc);
6d2010ae
A
174 return(error);
175}
176
39236c6e
A
177static int
178handle_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
179{
180 int error = 0;
181
182 switch(policy_subtype) {
183 case PROC_POLICY_RS_NONE:
184 case PROC_POLICY_RS_VIRTUALMEM:
185 break;
186 default:
187 return(EINVAL);
188 }
189
190 if (action == PROC_POLICY_ACTION_RESTORE)
191 error = proc_resetpcontrol(proc_pid(proc));
192 else
193 error = EINVAL;
194
195 return(error);
196}
197
198
199static int
200handle_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)
201{
39236c6e
A
202 proc_policy_cpuusage_attr_t cpuattr;
203#if CONFIG_MACF
204 proc_t curp = current_proc();
205#endif
206 int entitled = TRUE;
207 uint64_t interval = -1ULL;
208 int error = 0;
6d2010ae
A
209
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:
217 return(ENOTSUP);
218 break;
219 default:
220 return(EINVAL);
221 case PROC_POLICY_RUSAGE_CPU:
222 break;
223 }
224
39236c6e
A
225#if CONFIG_MACF
226 if (curp != proc) {
227 /* the cpumon entitlement manages messing with CPU limits on self */
228 error = mac_proc_check_sched(curp, proc);
229 if (error)
230 return error;
231 }
232
233 /*
234 * Allow a process to change CPU usage monitor parameters, unless a MAC policy
235 * overrides it with an entitlement check.
236 */
237 entitled = (mac_proc_check_cpumon(curp) == 0) ? TRUE : FALSE;
238#endif
239
6d2010ae 240 switch (action) {
39236c6e
A
241 uint8_t percentage;
242
6d2010ae
A
243 case PROC_POLICY_ACTION_GET:
244 error = proc_get_task_ruse_cpu(proc->task, &cpuattr.ppattr_cpu_attr,
39236c6e 245 &percentage,
6d2010ae
A
246 &cpuattr.ppattr_cpu_attr_interval,
247 &cpuattr.ppattr_cpu_attr_deadline);
39236c6e
A
248 if (error == 0) {
249 cpuattr.ppattr_cpu_percentage = percentage;
250 cpuattr.ppattr_cpu_attr_interval /= NSEC_PER_SEC;
6d2010ae 251 error = copyout((proc_policy_cpuusage_attr_t *)&cpuattr, (user_addr_t)attrp, sizeof(proc_policy_cpuusage_attr_t));
39236c6e 252 }
6d2010ae
A
253 break;
254
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));
39236c6e
A
258 if (error != 0) {
259 return (error);
260 }
261
262 /*
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.
266 */
267 if (cpuattr.ppattr_cpu_attr_interval != -1ULL) {
268 interval = cpuattr.ppattr_cpu_attr_interval * NSEC_PER_SEC;
269 } else {
270 interval = -1ULL;
271 }
6d2010ae 272
6d2010ae
A
273 error = proc_set_task_ruse_cpu(proc->task, cpuattr.ppattr_cpu_attr,
274 cpuattr.ppattr_cpu_percentage,
39236c6e
A
275 interval,
276 cpuattr.ppattr_cpu_attr_deadline,
277 entitled);
316670eb
A
278 break;
279
280 case PROC_POLICY_ACTION_RESTORE:
39236c6e 281 error = proc_clear_task_ruse_cpu(proc->task, entitled);
316670eb
A
282 break;
283
6d2010ae
A
284 default:
285 error = EINVAL;
286 break;
287
288 }
289
290 return(error);
291}
292
39236c6e
A
293
294static int
295handle_apptype( int scope,
296 int action,
297 __unused int policy,
298 int policy_subtype,
299 __unused user_addr_t attrp,
300 proc_t target_proc,
301 __unused uint64_t target_threadid)
316670eb 302{
39236c6e
A
303 int error = 0;
304
305 if (scope != PROC_POLICY_SCOPE_PROCESS)
306 return (EINVAL);
307
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)
312 return (EINVAL);
313 if (target_proc != current_proc())
314 return (EINVAL);
315
316 /* PROCESS ENABLE APPTYPE DONATEIMP */
317 task_importance_mark_donor(target_proc->task, TRUE);
318
319 return(0);
320
321 case PROC_POLICY_IOS_HOLDIMP:
322 if (action != PROC_POLICY_ACTION_ENABLE)
323 return (EINVAL);
324 if (target_proc != current_proc())
325 return (EINVAL);
326
327 /* PROCESS ENABLE APPTYPE HOLDIMP */
328 error = task_importance_hold_external_assertion(current_task(), 1);
329
330 return(error);
331
332 case PROC_POLICY_IOS_DROPIMP:
333 if (action != PROC_POLICY_ACTION_ENABLE)
334 return (EINVAL);
335 if (target_proc != current_proc())
336 return (EINVAL);
337
338 /* PROCESS ENABLE APPTYPE DROPIMP */
339 error = task_importance_drop_external_assertion(current_task(), 1);
340
341 return(error);
342
343 default:
344 /* continue to TAL handling */
345 break;
346 }
347
348 if (policy_subtype != PROC_POLICY_OSX_APPTYPE_TAL)
349 return (EINVAL);
316670eb 350
39236c6e
A
351 /* need to be super user to do this */
352 if (kauth_cred_issuser(kauth_cred_get()) == 0)
353 return (EPERM);
354
355 if (proc_task_is_tal(target_proc->task) == FALSE)
356 return (EINVAL);
357
358 switch (action) {
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,
363 TASK_POLICY_ENABLE);
364 break;
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);
370 break;
371 default:
372 return (EINVAL);
373 break;
374 }
375
376 return(0);
377}
378
379static int
380handle_boost(int scope,
381 int action,
382 __unused int policy,
383 int policy_subtype,
384 __unused user_addr_t attrp,
385 proc_t target_proc,
386 __unused uint64_t target_threadid)
387{
316670eb 388 int error = 0;
316670eb 389
39236c6e
A
390 assert(policy == PROC_POLICY_BOOST);
391
392 if (scope != PROC_POLICY_SCOPE_PROCESS)
393 return (EINVAL);
394
395 if (target_proc != current_proc())
396 return (EINVAL);
316670eb
A
397
398 switch(policy_subtype) {
39236c6e
A
399 case PROC_POLICY_IMP_IMPORTANT:
400 if (task_is_importance_receiver(target_proc->task) == FALSE)
401 return (EINVAL);
316670eb 402
316670eb 403 switch (action) {
39236c6e
A
404 case PROC_POLICY_ACTION_HOLD:
405 /* PROCESS HOLD BOOST IMPORTANT */
406 error = task_importance_hold_external_assertion(current_task(), 1);
316670eb 407 break;
39236c6e
A
408 case PROC_POLICY_ACTION_DROP:
409 /* PROCESS DROP BOOST IMPORTANT */
410 error = task_importance_drop_external_assertion(current_task(), 1);
316670eb 411 break;
316670eb 412 default:
39236c6e 413 error = (EINVAL);
316670eb
A
414 break;
415 }
416 break;
417
39236c6e 418 case PROC_POLICY_IMP_DONATION:
316670eb 419#if CONFIG_MACF
39236c6e
A
420 error = mac_proc_check_sched(current_proc(), target_proc);
421 if (error) return error;
316670eb 422#endif
39236c6e
A
423 switch (action) {
424 case PROC_POLICY_ACTION_SET:
425 /* PROCESS SET BOOST DONATION */
426 task_importance_mark_donor(target_proc->task, TRUE);
427 break;
428 default:
429 error = (EINVAL);
430 break;
316670eb
A
431 }
432 break;
433
316670eb 434 default:
39236c6e
A
435 error = (EINVAL);
436 break;
316670eb
A
437 }
438
316670eb
A
439 return(error);
440}
316670eb 441
6d2010ae 442
39236c6e
A
443/*
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.
448 */
449int
450proc_pidbackgrounded(pid_t pid, uint32_t* state)
6d2010ae 451{
39236c6e 452 proc_t target_proc = PROC_NULL;
6d2010ae 453
39236c6e
A
454 if (state == NULL)
455 return(EINVAL);
6d2010ae 456
39236c6e
A
457 target_proc = proc_find(pid);
458
459 if (target_proc == PROC_NULL)
460 return(ESRCH);
461
462 if ( proc_get_effective_task_policy(target_proc->task, TASK_POLICY_DARWIN_BG) ) {
463 *state = 1;
464 } else {
465 *state = 0;
6d2010ae 466 }
6d2010ae 467
39236c6e
A
468 proc_rele(target_proc);
469 return (0);
470}
316670eb 471
6d2010ae 472int
39236c6e 473proc_apply_resource_actions(void * bsdinfo, __unused int type, int action)
6d2010ae
A
474{
475 proc_t p = (proc_t)bsdinfo;
476
477 switch(action) {
478 case PROC_POLICY_RSRCACT_THROTTLE:
479 /* no need to do anything */
480 break;
481
482 case PROC_POLICY_RSRCACT_SUSPEND:
483 task_suspend(p->task);
484 break;
485
486 case PROC_POLICY_RSRCACT_TERMINATE:
487 psignal(p, SIGKILL);
488 break;
489
316670eb 490 case PROC_POLICY_RSRCACT_NOTIFY_KQ:
39236c6e 491 /* not implemented */
6d2010ae 492 break;
316670eb
A
493
494 case PROC_POLICY_RSRCACT_NOTIFY_EXC:
495 panic("shouldn't be applying exception notification to process!");
496 break;
6d2010ae
A
497 }
498
499 return(0);
500}
501
502
503int
504proc_restore_resource_actions(void * bsdinfo, __unused int type, int action)
505{
506 proc_t p = (proc_t)bsdinfo;
507
508 switch(action) {
509 case PROC_POLICY_RSRCACT_THROTTLE:
510 case PROC_POLICY_RSRCACT_TERMINATE:
316670eb
A
511 case PROC_POLICY_RSRCACT_NOTIFY_KQ:
512 case PROC_POLICY_RSRCACT_NOTIFY_EXC:
6d2010ae
A
513 /* no need to do anything */
514 break;
515
516 case PROC_POLICY_RSRCACT_SUSPEND:
517 task_resume(p->task);
518 break;
519
520 }
521
522 return(0);
523}
524