]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/process_policy.c
ffbd70e98f78dcf63e91a09644dc961bcc255444
[apple/xnu.git] / bsd / kern / process_policy.c
1 /*
2 * Copyright (c) 2005-2016 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>
38 #include <sys/proc.h>
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/kalloc.h>
53 #include <kern/assert.h>
54 #include <kern/policy_internal.h>
55
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>
74
75 static int handle_lowresource(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
76 static int handle_cpuuse(int action, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
77 static int handle_apptype(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
78 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
80 extern kern_return_t task_suspend(task_t);
81 extern kern_return_t task_resume(task_t);
82
83
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
94 /* system call implementation */
95 int
96 process_policy(__unused struct proc *p, struct process_policy_args * uap, __unused int32_t *retval)
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;
106 proc_t target_proc = PROC_NULL;
107 proc_t curp = current_proc();
108 kauth_cred_t my_cred;
109
110 if ((scope != PROC_POLICY_SCOPE_PROCESS) && (scope != PROC_POLICY_SCOPE_THREAD)) {
111 return(EINVAL);
112 }
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)
120 return(ESRCH);
121
122 my_cred = kauth_cred_get();
123
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) &&
130 (!kauth_cred_issuser(my_cred) && curp != p))
131 {
132 error = EPERM;
133 goto out;
134 }
135
136 #if CONFIG_MACF
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;
146 }
147 #endif /* CONFIG_MACF */
148
149 switch(policy) {
150 case PROC_POLICY_BACKGROUND:
151 error = ENOTSUP;
152 break;
153 case PROC_POLICY_HARDWARE_ACCESS:
154 error = ENOTSUP;
155 break;
156 case PROC_POLICY_RESOURCE_STARVATION:
157 error = handle_lowresource(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
158 break;
159 case PROC_POLICY_RESOURCE_USAGE:
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);
175 break;
176 case PROC_POLICY_APPTYPE:
177 error = handle_apptype(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
178 break;
179 case PROC_POLICY_BOOST:
180 error = handle_boost(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
181 break;
182 default:
183 error = EINVAL;
184 break;
185 }
186
187 out:
188 proc_rele(target_proc);
189 return(error);
190 }
191
192 static int
193 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)
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
214 static int
215 handle_cpuuse(int action, user_addr_t attrp, proc_t proc, __unused uint64_t target_threadid)
216 {
217 proc_policy_cpuusage_attr_t cpuattr;
218 #if CONFIG_MACF
219 proc_t curp = current_proc();
220 #endif
221 int entitled = FALSE;
222 Boolean canEnable = FALSE;
223 uint64_t interval = -1ULL;
224 int error = 0;
225 uint8_t percentage;
226
227 #if CONFIG_MACF
228 /*
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.
235 */
236 entitled = (mac_proc_check_cpumon(curp) == 0) ? TRUE : FALSE;
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 }
244 #endif
245
246 switch (action) {
247 case PROC_POLICY_ACTION_GET:
248 error = proc_get_task_ruse_cpu(proc->task, &cpuattr.ppattr_cpu_attr,
249 &percentage,
250 &cpuattr.ppattr_cpu_attr_interval,
251 &cpuattr.ppattr_cpu_attr_deadline);
252 if (error == 0) {
253 cpuattr.ppattr_cpu_percentage = percentage;
254 cpuattr.ppattr_cpu_attr_interval /= NSEC_PER_SEC;
255 error = copyout((proc_policy_cpuusage_attr_t *)&cpuattr, (user_addr_t)attrp, sizeof(proc_policy_cpuusage_attr_t));
256 }
257 break;
258
259 case PROC_POLICY_ACTION_APPLY:
260 case PROC_POLICY_ACTION_SET:
261 error = copyin((user_addr_t)attrp, (proc_policy_cpuusage_attr_t *)&cpuattr, sizeof(proc_policy_cpuusage_attr_t));
262 if (error != 0) {
263 return (error);
264 }
265
266 /*
267 * The process_policy API uses seconds as the units for the interval,
268 * but the mach task policy SPI uses nanoseconds. Do the conversion,
269 * but preserve -1 as it has special meaning.
270 */
271 if (cpuattr.ppattr_cpu_attr_interval != -1ULL) {
272 interval = cpuattr.ppattr_cpu_attr_interval * NSEC_PER_SEC;
273 } else {
274 interval = -1ULL;
275 }
276
277 error = proc_set_task_ruse_cpu(proc->task, cpuattr.ppattr_cpu_attr,
278 cpuattr.ppattr_cpu_percentage,
279 interval,
280 cpuattr.ppattr_cpu_attr_deadline,
281 entitled);
282 break;
283
284 /* restore process to prior state */
285 case PROC_POLICY_ACTION_RESTORE:
286 error = proc_clear_task_ruse_cpu(proc->task, entitled);
287 break;
288
289 /* re-enable suspended monitor */
290 case PROC_POLICY_ACTION_ENABLE:
291 error = task_resume_cpumon(proc->task);
292 break;
293
294 case PROC_POLICY_ACTION_REMOVE:
295
296 default:
297 error = EINVAL;
298 break;
299
300 }
301
302 return(error);
303 }
304
305
306 static int
307 handle_apptype( int scope,
308 int action,
309 __unused int policy,
310 int policy_subtype,
311 __unused user_addr_t attrp,
312 proc_t target_proc,
313 __unused uint64_t target_threadid)
314 {
315 int error = 0;
316
317 if (scope != PROC_POLICY_SCOPE_PROCESS)
318 return (EINVAL);
319
320 /* Temporary compatibility with old importance donation interface until libproc is moved to new boost calls */
321 switch (policy_subtype) {
322 case PROC_POLICY_IOS_DONATEIMP:
323 if (action != PROC_POLICY_ACTION_ENABLE)
324 return (EINVAL);
325 if (target_proc != current_proc())
326 return (EINVAL);
327
328 /* PROCESS ENABLE APPTYPE DONATEIMP */
329 task_importance_mark_donor(target_proc->task, TRUE);
330
331 return(0);
332
333 case PROC_POLICY_IOS_HOLDIMP:
334 if (action != PROC_POLICY_ACTION_ENABLE)
335 return (EINVAL);
336 if (target_proc != current_proc())
337 return (EINVAL);
338
339 /* PROCESS ENABLE APPTYPE HOLDIMP */
340 error = task_importance_hold_legacy_external_assertion(current_task(), 1);
341
342 return(error);
343
344 case PROC_POLICY_IOS_DROPIMP:
345 if (action != PROC_POLICY_ACTION_ENABLE)
346 return (EINVAL);
347 if (target_proc != current_proc())
348 return (EINVAL);
349
350 /* PROCESS ENABLE APPTYPE DROPIMP */
351 error = task_importance_drop_legacy_external_assertion(current_task(), 1);
352
353 return(error);
354
355 default:
356 /* continue to TAL handling */
357 break;
358 }
359
360 if (policy_subtype != PROC_POLICY_OSX_APPTYPE_TAL)
361 return (EINVAL);
362
363 /* need to be super user to do this */
364 if (kauth_cred_issuser(kauth_cred_get()) == 0)
365 return (EPERM);
366
367 if (proc_task_is_tal(target_proc->task) == FALSE)
368 return (EINVAL);
369
370 switch (action) {
371 case PROC_POLICY_ACTION_ENABLE:
372 /* PROCESS ENABLE APPTYPE TAL */
373 proc_set_task_policy(target_proc->task,
374 TASK_POLICY_ATTRIBUTE, TASK_POLICY_TAL,
375 TASK_POLICY_ENABLE);
376 break;
377 case PROC_POLICY_ACTION_DISABLE:
378 /* PROCESS DISABLE APPTYPE TAL */
379 proc_set_task_policy(target_proc->task,
380 TASK_POLICY_ATTRIBUTE, TASK_POLICY_TAL,
381 TASK_POLICY_DISABLE);
382 break;
383 default:
384 return (EINVAL);
385 }
386
387 return(0);
388 }
389
390 static int
391 handle_boost(int scope,
392 int action,
393 __unused int policy,
394 int policy_subtype,
395 __unused user_addr_t attrp,
396 proc_t target_proc,
397 __unused uint64_t target_threadid)
398 {
399 int error = 0;
400
401 assert(policy == PROC_POLICY_BOOST);
402
403 if (scope != PROC_POLICY_SCOPE_PROCESS)
404 return (EINVAL);
405
406 if (target_proc != current_proc())
407 return (EINVAL);
408
409 switch(policy_subtype) {
410 case PROC_POLICY_IMP_IMPORTANT:
411 if (task_is_importance_receiver_type(target_proc->task) == FALSE)
412 return (EINVAL);
413
414 switch (action) {
415 case PROC_POLICY_ACTION_HOLD:
416 /* PROCESS HOLD BOOST IMPORTANT */
417 error = task_importance_hold_legacy_external_assertion(current_task(), 1);
418 break;
419 case PROC_POLICY_ACTION_DROP:
420 /* PROCESS DROP BOOST IMPORTANT */
421 error = task_importance_drop_legacy_external_assertion(current_task(), 1);
422 break;
423 default:
424 error = (EINVAL);
425 break;
426 }
427 break;
428
429 case PROC_POLICY_IMP_DONATION:
430 #if CONFIG_MACF
431 error = mac_proc_check_sched(current_proc(), target_proc);
432 if (error) return error;
433 #endif
434 switch (action) {
435 case PROC_POLICY_ACTION_SET:
436 /* PROCESS SET BOOST DONATION */
437 task_importance_mark_donor(target_proc->task, TRUE);
438 break;
439 default:
440 error = (EINVAL);
441 break;
442 }
443 break;
444
445 default:
446 error = (EINVAL);
447 break;
448 }
449
450 return(error);
451 }
452
453
454 /*
455 * KPI to determine if a pid is currently backgrounded.
456 * Returns ESRCH if pid cannot be found or has started exiting.
457 * Returns EINVAL if state is NULL.
458 * Sets *state to 1 if pid is backgrounded, and 0 otherwise.
459 */
460 int
461 proc_pidbackgrounded(pid_t pid, uint32_t* state)
462 {
463 proc_t target_proc = PROC_NULL;
464
465 if (state == NULL)
466 return(EINVAL);
467
468 target_proc = proc_find(pid);
469
470 if (target_proc == PROC_NULL)
471 return(ESRCH);
472
473 if ( proc_get_effective_task_policy(target_proc->task, TASK_POLICY_DARWIN_BG) ) {
474 *state = 1;
475 } else {
476 *state = 0;
477 }
478
479 proc_rele(target_proc);
480 return (0);
481 }
482
483 /*
484 * Get the darwin background state of the originator. If the current
485 * process app type is App, then it is the originator, else if it is
486 * a Daemon, then creator of the Resource Accounting attribute of
487 * the current thread voucher is the originator of the work.
488 */
489 int
490 proc_get_originatorbgstate(uint32_t *is_backgrounded)
491 {
492 uint32_t bgstate;
493 proc_t p = current_proc();
494 uint32_t flagsp;
495 kern_return_t kr;
496 pid_t pid;
497 int ret;
498 thread_t thread = current_thread();
499
500 bgstate = proc_get_effective_thread_policy(thread, TASK_POLICY_DARWIN_BG);
501
502 /* If current thread or task backgrounded, return background */
503 if (bgstate) {
504 *is_backgrounded = 1;
505 return 0;
506 }
507
508 /* Check if current process app type is App, then return foreground */
509 proc_get_darwinbgstate(p->task, &flagsp);
510 if ((flagsp & PROC_FLAG_APPLICATION) == PROC_FLAG_APPLICATION) {
511 *is_backgrounded = 0;
512 return 0;
513 }
514
515 /*
516 * Get the current voucher origin pid and it's bgstate.The pid
517 * returned here might not be valid or may have been recycled.
518 */
519 kr = thread_get_current_voucher_origin_pid(&pid);
520 if (kr != KERN_SUCCESS) {
521 if (kr == KERN_INVALID_TASK)
522 return ESRCH;
523 else if (kr == KERN_INVALID_VALUE)
524 return ENOATTR;
525 else
526 return EINVAL;
527 }
528
529 ret = proc_pidbackgrounded(pid, is_backgrounded);
530 return ret;
531 }
532
533 int
534 proc_apply_resource_actions(void * bsdinfo, __unused int type, int action)
535 {
536 proc_t p = (proc_t)bsdinfo;
537
538 switch(action) {
539 case PROC_POLICY_RSRCACT_THROTTLE:
540 /* no need to do anything */
541 break;
542
543 case PROC_POLICY_RSRCACT_SUSPEND:
544 task_suspend(p->task);
545 break;
546
547 case PROC_POLICY_RSRCACT_TERMINATE:
548 psignal(p, SIGKILL);
549 break;
550
551 case PROC_POLICY_RSRCACT_NOTIFY_KQ:
552 /* not implemented */
553 break;
554
555 case PROC_POLICY_RSRCACT_NOTIFY_EXC:
556 panic("shouldn't be applying exception notification to process!");
557 break;
558 }
559
560 return(0);
561 }
562
563 int
564 proc_restore_resource_actions(void * bsdinfo, __unused int type, int action)
565 {
566 proc_t p = (proc_t)bsdinfo;
567
568 switch(action) {
569 case PROC_POLICY_RSRCACT_THROTTLE:
570 case PROC_POLICY_RSRCACT_TERMINATE:
571 case PROC_POLICY_RSRCACT_NOTIFY_KQ:
572 case PROC_POLICY_RSRCACT_NOTIFY_EXC:
573 /* no need to do anything */
574 break;
575
576 case PROC_POLICY_RSRCACT_SUSPEND:
577 task_resume(p->task);
578 break;
579
580 }
581
582 return(0);
583 }
584