]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/process_policy.c
xnu-2782.40.9.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>
6d2010ae
A
52#include <kern/kalloc.h>
53#include <kern/assert.h>
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>
39236c6e
A
72
73static 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
74static int handle_resourceuse(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
75static int handle_apptype(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
39236c6e 76static 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
77
78extern kern_return_t task_suspend(task_t);
79extern kern_return_t task_resume(task_t);
80
316670eb 81
6d2010ae
A
82/***************************** process_policy ********************/
83
84/*
85 *int process_policy(int scope, int action, int policy, int policy_subtype,
86 * proc_policy_attribute_t * attrp, pid_t target_pid,
87 * uint64_t target_threadid)
88 *{ int process_policy(int scope, int action, int policy, int policy_subtype,
89 * user_addr_t attrp, pid_t target_pid, uint64_t target_threadid); }
90 */
91
39236c6e 92/* system call implementation */
6d2010ae 93int
316670eb 94process_policy(__unused struct proc *p, struct process_policy_args * uap, __unused int32_t *retval)
6d2010ae
A
95{
96 int error = 0;
97 int scope = uap->scope;
98 int policy = uap->policy;
99 int action = uap->action;
100 int policy_subtype = uap->policy_subtype;
101 user_addr_t attrp = uap->attrp;
102 pid_t target_pid = uap->target_pid;
103 uint64_t target_threadid = uap->target_threadid;
316670eb 104 proc_t target_proc = PROC_NULL;
6d2010ae
A
105 proc_t curp = current_proc();
106 kauth_cred_t my_cred;
6d2010ae
A
107
108 if ((scope != PROC_POLICY_SCOPE_PROCESS) && (scope != PROC_POLICY_SCOPE_THREAD)) {
109 return(EINVAL);
110 }
39236c6e
A
111
112 if (target_pid == 0 || target_pid == proc_selfpid())
113 target_proc = proc_self();
114 else
115 target_proc = proc_find(target_pid);
116
117 if (target_proc == PROC_NULL)
316670eb 118 return(ESRCH);
6d2010ae 119
316670eb 120 my_cred = kauth_cred_get();
6d2010ae 121
6d2010ae
A
122 /*
123 * Resoure starvation control can be used by unpriv resource owner but priv at the time of ownership claim. This is
124 * checked in low resource handle routine. So bypass the checks here.
125 */
126 if ((policy != PROC_POLICY_RESOURCE_STARVATION) &&
127 (policy != PROC_POLICY_APPTYPE) &&
316670eb 128 (!kauth_cred_issuser(my_cred) && curp != p))
6d2010ae
A
129 {
130 error = EPERM;
131 goto out;
132 }
133
134#if CONFIG_MACF
39236c6e
A
135 switch (policy) {
136 case PROC_POLICY_BOOST:
137 case PROC_POLICY_RESOURCE_USAGE:
138 /* These policies do their own appropriate mac checks */
139 break;
140 default:
141 error = mac_proc_check_sched(curp, target_proc);
142 if (error) goto out;
143 break;
316670eb 144 }
316670eb 145#endif /* CONFIG_MACF */
6d2010ae 146
6d2010ae
A
147 switch(policy) {
148 case PROC_POLICY_BACKGROUND:
39236c6e 149 error = ENOTSUP;
6d2010ae
A
150 break;
151 case PROC_POLICY_HARDWARE_ACCESS:
39236c6e 152 error = ENOTSUP;
6d2010ae
A
153 break;
154 case PROC_POLICY_RESOURCE_STARVATION:
39236c6e 155 error = handle_lowresource(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
6d2010ae
A
156 break;
157 case PROC_POLICY_RESOURCE_USAGE:
316670eb
A
158 error = handle_resourceuse(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
159 break;
6d2010ae 160 case PROC_POLICY_APPTYPE:
316670eb 161 error = handle_apptype(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
6d2010ae 162 break;
39236c6e
A
163 case PROC_POLICY_BOOST:
164 error = handle_boost(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
165 break;
6d2010ae
A
166 default:
167 error = EINVAL;
168 break;
169 }
170
171out:
316670eb 172 proc_rele(target_proc);
6d2010ae
A
173 return(error);
174}
175
39236c6e
A
176static int
177handle_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
178{
179 int error = 0;
180
181 switch(policy_subtype) {
182 case PROC_POLICY_RS_NONE:
183 case PROC_POLICY_RS_VIRTUALMEM:
184 break;
185 default:
186 return(EINVAL);
187 }
188
189 if (action == PROC_POLICY_ACTION_RESTORE)
190 error = proc_resetpcontrol(proc_pid(proc));
191 else
192 error = EINVAL;
193
194 return(error);
195}
196
197
198static int
199handle_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)
200{
39236c6e
A
201 proc_policy_cpuusage_attr_t cpuattr;
202#if CONFIG_MACF
203 proc_t curp = current_proc();
204#endif
205 int entitled = TRUE;
206 uint64_t interval = -1ULL;
207 int error = 0;
fe8ab488 208 uint8_t percentage;
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
A
240 switch (action) {
241 case PROC_POLICY_ACTION_GET:
242 error = proc_get_task_ruse_cpu(proc->task, &cpuattr.ppattr_cpu_attr,
39236c6e 243 &percentage,
6d2010ae
A
244 &cpuattr.ppattr_cpu_attr_interval,
245 &cpuattr.ppattr_cpu_attr_deadline);
39236c6e
A
246 if (error == 0) {
247 cpuattr.ppattr_cpu_percentage = percentage;
248 cpuattr.ppattr_cpu_attr_interval /= NSEC_PER_SEC;
6d2010ae 249 error = copyout((proc_policy_cpuusage_attr_t *)&cpuattr, (user_addr_t)attrp, sizeof(proc_policy_cpuusage_attr_t));
39236c6e 250 }
6d2010ae
A
251 break;
252
253 case PROC_POLICY_ACTION_APPLY:
254 case PROC_POLICY_ACTION_SET:
255 error = copyin((user_addr_t)attrp, (proc_policy_cpuusage_attr_t *)&cpuattr, sizeof(proc_policy_cpuusage_attr_t));
39236c6e
A
256 if (error != 0) {
257 return (error);
258 }
259
260 /*
261 * The process_policy API uses seconds as the units for the interval,
262 * but the mach task policy SPI uses nanoseconds. Do the conversion,
263 * but preserve -1 as it has special meaning.
264 */
265 if (cpuattr.ppattr_cpu_attr_interval != -1ULL) {
266 interval = cpuattr.ppattr_cpu_attr_interval * NSEC_PER_SEC;
267 } else {
268 interval = -1ULL;
269 }
6d2010ae 270
6d2010ae
A
271 error = proc_set_task_ruse_cpu(proc->task, cpuattr.ppattr_cpu_attr,
272 cpuattr.ppattr_cpu_percentage,
39236c6e
A
273 interval,
274 cpuattr.ppattr_cpu_attr_deadline,
275 entitled);
316670eb
A
276 break;
277
278 case PROC_POLICY_ACTION_RESTORE:
39236c6e 279 error = proc_clear_task_ruse_cpu(proc->task, entitled);
316670eb
A
280 break;
281
6d2010ae
A
282 default:
283 error = EINVAL;
284 break;
285
286 }
287
288 return(error);
289}
290
39236c6e
A
291
292static int
293handle_apptype( int scope,
294 int action,
295 __unused int policy,
296 int policy_subtype,
297 __unused user_addr_t attrp,
298 proc_t target_proc,
299 __unused uint64_t target_threadid)
316670eb 300{
39236c6e
A
301 int error = 0;
302
303 if (scope != PROC_POLICY_SCOPE_PROCESS)
304 return (EINVAL);
305
306 /* Temporary compatibility with old importance donation interface until libproc is moved to new boost calls */
307 switch (policy_subtype) {
308 case PROC_POLICY_IOS_DONATEIMP:
309 if (action != PROC_POLICY_ACTION_ENABLE)
310 return (EINVAL);
311 if (target_proc != current_proc())
312 return (EINVAL);
313
314 /* PROCESS ENABLE APPTYPE DONATEIMP */
315 task_importance_mark_donor(target_proc->task, TRUE);
316
317 return(0);
318
319 case PROC_POLICY_IOS_HOLDIMP:
320 if (action != PROC_POLICY_ACTION_ENABLE)
321 return (EINVAL);
322 if (target_proc != current_proc())
323 return (EINVAL);
324
325 /* PROCESS ENABLE APPTYPE HOLDIMP */
fe8ab488 326 error = task_importance_hold_legacy_external_assertion(current_task(), 1);
39236c6e
A
327
328 return(error);
329
330 case PROC_POLICY_IOS_DROPIMP:
331 if (action != PROC_POLICY_ACTION_ENABLE)
332 return (EINVAL);
333 if (target_proc != current_proc())
334 return (EINVAL);
335
336 /* PROCESS ENABLE APPTYPE DROPIMP */
fe8ab488 337 error = task_importance_drop_legacy_external_assertion(current_task(), 1);
39236c6e
A
338
339 return(error);
340
341 default:
342 /* continue to TAL handling */
343 break;
344 }
345
346 if (policy_subtype != PROC_POLICY_OSX_APPTYPE_TAL)
347 return (EINVAL);
316670eb 348
39236c6e
A
349 /* need to be super user to do this */
350 if (kauth_cred_issuser(kauth_cred_get()) == 0)
351 return (EPERM);
352
353 if (proc_task_is_tal(target_proc->task) == FALSE)
354 return (EINVAL);
355
356 switch (action) {
357 case PROC_POLICY_ACTION_ENABLE:
358 /* PROCESS ENABLE APPTYPE TAL */
359 proc_set_task_policy(target_proc->task, THREAD_NULL,
360 TASK_POLICY_ATTRIBUTE, TASK_POLICY_TAL,
361 TASK_POLICY_ENABLE);
362 break;
363 case PROC_POLICY_ACTION_DISABLE:
364 /* PROCESS DISABLE APPTYPE TAL */
365 proc_set_task_policy(target_proc->task, THREAD_NULL,
366 TASK_POLICY_ATTRIBUTE, TASK_POLICY_TAL,
367 TASK_POLICY_DISABLE);
368 break;
369 default:
370 return (EINVAL);
371 break;
372 }
373
374 return(0);
375}
376
377static int
378handle_boost(int scope,
379 int action,
380 __unused int policy,
381 int policy_subtype,
382 __unused user_addr_t attrp,
383 proc_t target_proc,
384 __unused uint64_t target_threadid)
385{
316670eb 386 int error = 0;
316670eb 387
39236c6e
A
388 assert(policy == PROC_POLICY_BOOST);
389
390 if (scope != PROC_POLICY_SCOPE_PROCESS)
391 return (EINVAL);
392
393 if (target_proc != current_proc())
394 return (EINVAL);
316670eb
A
395
396 switch(policy_subtype) {
39236c6e 397 case PROC_POLICY_IMP_IMPORTANT:
fe8ab488 398 if (task_is_importance_receiver_type(target_proc->task) == FALSE)
39236c6e 399 return (EINVAL);
316670eb 400
316670eb 401 switch (action) {
39236c6e
A
402 case PROC_POLICY_ACTION_HOLD:
403 /* PROCESS HOLD BOOST IMPORTANT */
fe8ab488 404 error = task_importance_hold_legacy_external_assertion(current_task(), 1);
316670eb 405 break;
39236c6e
A
406 case PROC_POLICY_ACTION_DROP:
407 /* PROCESS DROP BOOST IMPORTANT */
fe8ab488 408 error = task_importance_drop_legacy_external_assertion(current_task(), 1);
316670eb 409 break;
316670eb 410 default:
39236c6e 411 error = (EINVAL);
316670eb
A
412 break;
413 }
414 break;
415
39236c6e 416 case PROC_POLICY_IMP_DONATION:
316670eb 417#if CONFIG_MACF
39236c6e
A
418 error = mac_proc_check_sched(current_proc(), target_proc);
419 if (error) return error;
316670eb 420#endif
39236c6e
A
421 switch (action) {
422 case PROC_POLICY_ACTION_SET:
423 /* PROCESS SET BOOST DONATION */
424 task_importance_mark_donor(target_proc->task, TRUE);
425 break;
426 default:
427 error = (EINVAL);
428 break;
316670eb
A
429 }
430 break;
431
316670eb 432 default:
39236c6e
A
433 error = (EINVAL);
434 break;
316670eb
A
435 }
436
316670eb
A
437 return(error);
438}
316670eb 439
6d2010ae 440
39236c6e
A
441/*
442 * KPI to determine if a pid is currently backgrounded.
443 * Returns ESRCH if pid cannot be found or has started exiting.
444 * Returns EINVAL if state is NULL.
445 * Sets *state to 1 if pid is backgrounded, and 0 otherwise.
446 */
447int
448proc_pidbackgrounded(pid_t pid, uint32_t* state)
6d2010ae 449{
39236c6e 450 proc_t target_proc = PROC_NULL;
6d2010ae 451
39236c6e
A
452 if (state == NULL)
453 return(EINVAL);
6d2010ae 454
39236c6e
A
455 target_proc = proc_find(pid);
456
457 if (target_proc == PROC_NULL)
458 return(ESRCH);
459
460 if ( proc_get_effective_task_policy(target_proc->task, TASK_POLICY_DARWIN_BG) ) {
461 *state = 1;
462 } else {
463 *state = 0;
6d2010ae 464 }
6d2010ae 465
39236c6e
A
466 proc_rele(target_proc);
467 return (0);
468}
316670eb 469
fe8ab488
A
470/*
471 * Get the darwin background state of the originator. If the current
472 * process app type is App, then it is the originator, else if it is
473 * a Daemon, then creator of the Resource Accounting attribute of
474 * the current thread voucher is the originator of the work.
475 */
476int
477proc_get_originatorbgstate(uint32_t *is_backgrounded)
478{
479 uint32_t bgstate;
480 proc_t p = current_proc();
481 uint32_t flagsp;
482 kern_return_t kr;
483 pid_t pid;
484 int ret;
485 thread_t thread = current_thread();
486
487 bgstate = proc_get_effective_thread_policy(thread, TASK_POLICY_DARWIN_BG);
488
489 /* If current thread or task backgrounded, return background */
490 if (bgstate) {
491 *is_backgrounded = 1;
492 return 0;
493 }
494
495 /* Check if current process app type is App, then return foreground */
496 proc_get_darwinbgstate(p->task, &flagsp);
497 if ((flagsp & PROC_FLAG_APPLICATION) == PROC_FLAG_APPLICATION) {
498 *is_backgrounded = 0;
499 return 0;
500 }
501
502 /*
503 * Get the current voucher origin pid and it's bgstate.The pid
504 * returned here might not be valid or may have been recycled.
505 */
506 kr = thread_get_current_voucher_origin_pid(&pid);
507 if (kr != KERN_SUCCESS) {
508 if (kr == KERN_INVALID_TASK)
509 return ESRCH;
510 else if (kr == KERN_INVALID_VALUE)
511 return ENOATTR;
512 else
513 return EINVAL;
514 }
515
516 ret = proc_pidbackgrounded(pid, is_backgrounded);
517 return ret;
518}
519
6d2010ae 520int
39236c6e 521proc_apply_resource_actions(void * bsdinfo, __unused int type, int action)
6d2010ae
A
522{
523 proc_t p = (proc_t)bsdinfo;
524
525 switch(action) {
526 case PROC_POLICY_RSRCACT_THROTTLE:
527 /* no need to do anything */
528 break;
529
530 case PROC_POLICY_RSRCACT_SUSPEND:
531 task_suspend(p->task);
532 break;
533
534 case PROC_POLICY_RSRCACT_TERMINATE:
535 psignal(p, SIGKILL);
536 break;
537
316670eb 538 case PROC_POLICY_RSRCACT_NOTIFY_KQ:
39236c6e 539 /* not implemented */
6d2010ae 540 break;
316670eb
A
541
542 case PROC_POLICY_RSRCACT_NOTIFY_EXC:
543 panic("shouldn't be applying exception notification to process!");
544 break;
6d2010ae
A
545 }
546
547 return(0);
548}
549
6d2010ae
A
550int
551proc_restore_resource_actions(void * bsdinfo, __unused int type, int action)
552{
553 proc_t p = (proc_t)bsdinfo;
554
555 switch(action) {
556 case PROC_POLICY_RSRCACT_THROTTLE:
557 case PROC_POLICY_RSRCACT_TERMINATE:
316670eb
A
558 case PROC_POLICY_RSRCACT_NOTIFY_KQ:
559 case PROC_POLICY_RSRCACT_NOTIFY_EXC:
6d2010ae
A
560 /* no need to do anything */
561 break;
562
563 case PROC_POLICY_RSRCACT_SUSPEND:
564 task_resume(p->task);
565 break;
566
567 }
568
569 return(0);
570}
571