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