]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/process_policy.c
ff919538fb4c1918dfff316766606b5a36ab2c66
[apple/xnu.git] / bsd / kern / process_policy.c
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>
38 #include <sys/kauth.h>
39 #include <sys/unistd.h>
40 #include <sys/buf.h>
41 #include <sys/ioctl.h>
42 #include <sys/vm.h>
43 #include <sys/user.h>
44
45 #include <security/audit/audit.h>
46
47 #include <mach/machine.h>
48 #include <mach/mach_types.h>
49 #include <mach/vm_param.h>
50 #include <kern/task.h>
51 #include <kern/lock.h>
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>
72 #if CONFIG_EMBEDDED
73 #include <security/mac.h>
74 #include <sys/kern_memorystatus.h>
75 #endif /* CONFIG_EMBEDDED */
76
77 static int handle_background(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
78 static int handle_hwaccess(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
79 static int handle_lowresrouce(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
80 static int handle_resourceuse(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
81 static int handle_apptype(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
82
83 extern kern_return_t task_suspend(task_t);
84 extern kern_return_t task_resume(task_t);
85
86 #if CONFIG_EMBEDDED
87 static int handle_applifecycle(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
88 #endif /* CONFIG_EMBEDDED */
89
90
91 /***************************** process_policy ********************/
92
93 /*
94 *int process_policy(int scope, int action, int policy, int policy_subtype,
95 * proc_policy_attribute_t * attrp, pid_t target_pid,
96 * uint64_t target_threadid)
97 *{ int process_policy(int scope, int action, int policy, int policy_subtype,
98 * user_addr_t attrp, pid_t target_pid, uint64_t target_threadid); }
99 */
100
101 /* system call implementaion */
102 int
103 process_policy(__unused struct proc *p, struct process_policy_args * uap, __unused int32_t *retval)
104 {
105 int error = 0;
106 int scope = uap->scope;
107 int policy = uap->policy;
108 int action = uap->action;
109 int policy_subtype = uap->policy_subtype;
110 user_addr_t attrp = uap->attrp;
111 pid_t target_pid = uap->target_pid;
112 uint64_t target_threadid = uap->target_threadid;
113 proc_t target_proc = PROC_NULL;
114 proc_t curp = current_proc();
115 kauth_cred_t my_cred;
116 #if CONFIG_EMBEDDED
117 kauth_cred_t target_cred;
118 #endif
119
120 if ((scope != PROC_POLICY_SCOPE_PROCESS) && (scope != PROC_POLICY_SCOPE_THREAD)) {
121 return(EINVAL);
122 }
123 target_proc = proc_find(target_pid);
124 if (target_proc == PROC_NULL) {
125 return(ESRCH);
126 }
127
128 my_cred = kauth_cred_get();
129
130 #if CONFIG_EMBEDDED
131 target_cred = kauth_cred_proc_ref(target_proc);
132
133 if (!kauth_cred_issuser(my_cred) && kauth_cred_getruid(my_cred) &&
134 kauth_cred_getuid(my_cred) != kauth_cred_getuid(target_cred) &&
135 kauth_cred_getruid(my_cred) != kauth_cred_getuid(target_cred))
136 #else
137 /*
138 * Resoure starvation control can be used by unpriv resource owner but priv at the time of ownership claim. This is
139 * checked in low resource handle routine. So bypass the checks here.
140 */
141 if ((policy != PROC_POLICY_RESOURCE_STARVATION) &&
142 (policy != PROC_POLICY_APPTYPE) &&
143 (!kauth_cred_issuser(my_cred) && curp != p))
144 #endif
145 {
146 error = EPERM;
147 goto out;
148 }
149
150 #if CONFIG_MACF
151 #if CONFIG_EMBEDDED
152 /* Lifecycle management will invoke approp macf checks */
153 if (policy != PROC_POLICY_APP_LIFECYCLE) {
154 #endif /* CONFIG_EMBEDDED */
155 error = mac_proc_check_sched(curp, target_proc);
156 if (error)
157 goto out;
158 #if CONFIG_EMBEDDED
159 }
160 #endif /* CONFIG_EMBEDDED */
161 #endif /* CONFIG_MACF */
162
163
164 switch(policy) {
165 case PROC_POLICY_BACKGROUND:
166 error = handle_background(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
167 break;
168 case PROC_POLICY_HARDWARE_ACCESS:
169 error = handle_hwaccess(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
170 break;
171 case PROC_POLICY_RESOURCE_STARVATION:
172 error = handle_lowresrouce(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
173 break;
174 case PROC_POLICY_RESOURCE_USAGE:
175 error = handle_resourceuse(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
176 break;
177 #if CONFIG_EMBEDDED
178 case PROC_POLICY_APP_LIFECYCLE:
179 error = handle_applifecycle(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
180 break;
181 #endif /* CONFIG_EMBEDDED */
182 case PROC_POLICY_APPTYPE:
183 error = handle_apptype(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
184 break;
185 default:
186 error = EINVAL;
187 break;
188 }
189
190 out:
191 proc_rele(target_proc);
192 #if CONFIG_EMBEDDED
193 kauth_cred_unref(&target_cred);
194 #endif
195 return(error);
196 }
197
198
199 /* darwin background handling code */
200 static int
201 handle_background(int scope, int action, __unused int policy, __unused int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid)
202 {
203 int intval, error = 0;
204
205
206 switch (action) {
207 case PROC_POLICY_ACTION_GET:
208 if (scope == PROC_POLICY_SCOPE_PROCESS) {
209 intval = proc_get_task_bg_policy(proc->task);
210 } else {
211 /* thread scope */
212 intval = proc_get_thread_bg_policy(proc->task, target_threadid);
213 }
214 error = copyout((int *)&intval, (user_addr_t)attrp, sizeof(int));
215 break;
216
217 case PROC_POLICY_ACTION_SET:
218 error = copyin((user_addr_t)attrp, (int *)&intval, sizeof(int));
219 if (error != 0)
220 goto out;
221 if (intval > PROC_POLICY_BG_ALL) {
222 error = EINVAL;
223 goto out;
224 }
225 if (scope == PROC_POLICY_SCOPE_PROCESS) {
226 error = proc_set_bgtaskpolicy(proc->task, intval);
227 } else {
228 /* thread scope */
229 error = proc_set_bgthreadpolicy(proc->task, target_threadid, intval);
230 }
231 break;
232
233 case PROC_POLICY_ACTION_ADD:
234 error = copyin((user_addr_t)attrp, (int *)&intval, sizeof(int));
235 if (error != 0)
236 goto out;
237 if (intval > PROC_POLICY_BG_ALL) {
238 error = EINVAL;
239 goto out;
240 }
241 if (scope == PROC_POLICY_SCOPE_PROCESS) {
242 error = proc_add_bgtaskpolicy(proc->task, intval);
243 } else {
244 /* thread scope */
245 error = proc_add_bgthreadpolicy(proc->task, target_threadid, intval);
246 }
247 break;
248
249 case PROC_POLICY_ACTION_REMOVE:
250 error = copyin((user_addr_t)attrp, (int *)&intval, sizeof(int));
251 if (error != 0)
252 goto out;
253 if (intval > PROC_POLICY_BG_ALL) {
254 error = EINVAL;
255 goto out;
256 }
257 if (scope == PROC_POLICY_SCOPE_PROCESS) {
258 error = proc_remove_bgtaskpolicy(proc->task, intval);
259 } else {
260 /* thread scope */
261 error = proc_remove_bgthreadpolicy(proc->task, target_threadid, intval);
262 }
263 break;
264
265 case PROC_POLICY_ACTION_APPLY:
266 if (scope == PROC_POLICY_SCOPE_PROCESS) {
267 error = proc_apply_bgtaskpolicy(proc->task);
268 } else {
269 /* thread scope */
270 error = proc_apply_bgthreadpolicy(proc->task, target_threadid);
271 }
272 break;
273
274 case PROC_POLICY_ACTION_RESTORE:
275 if (scope == PROC_POLICY_SCOPE_PROCESS) {
276 error = proc_restore_bgtaskpolicy(proc->task);
277 } else {
278 /* thread scope */
279 error = proc_restore_bgthreadpolicy(proc->task, target_threadid);
280 }
281 break;
282
283 case PROC_POLICY_ACTION_DENYINHERIT:
284 error = proc_denyinherit_policy(proc->task);
285 break;
286
287 case PROC_POLICY_ACTION_DENYSELFSET:
288 error = proc_denyselfset_policy(proc->task);
289 break;
290
291 default:
292 return(EINVAL);
293 }
294
295 out:
296 return(error);
297 }
298
299 static int
300 handle_hwaccess(__unused int scope, __unused int action, __unused int policy, int policy_subtype, __unused user_addr_t attrp, __unused proc_t proc, __unused uint64_t target_threadid)
301 {
302 switch(policy_subtype) {
303 case PROC_POLICY_HWACCESS_NONE:
304 case PROC_POLICY_HWACCESS_DISK:
305 case PROC_POLICY_HWACCESS_GPU:
306 case PROC_POLICY_HWACCESS_NETWORK:
307 case PROC_POLICY_HWACCESS_CPU:
308 break;
309 default:
310 return(EINVAL);
311 }
312 return(0);
313 }
314
315 static int
316 handle_lowresrouce(__unused int scope, int action, __unused int policy, int policy_subtype, __unused user_addr_t attrp, proc_t proc, __unused uint64_t target_threadid)
317 {
318 int error = 0;
319
320 switch(policy_subtype) {
321 case PROC_POLICY_RS_NONE:
322 case PROC_POLICY_RS_VIRTUALMEM:
323 break;
324 default:
325 return(EINVAL);
326 }
327
328 if (action == PROC_POLICY_ACTION_RESTORE)
329 error = proc_resetpcontrol(proc_pid(proc));
330 else
331 error = EINVAL;
332
333 return(error);
334 }
335
336
337 static int
338 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)
339 {
340 proc_policy_cpuusage_attr_t cpuattr;
341 int error = 0;
342
343 switch(policy_subtype) {
344 case PROC_POLICY_RUSAGE_NONE:
345 case PROC_POLICY_RUSAGE_WIREDMEM:
346 case PROC_POLICY_RUSAGE_VIRTMEM:
347 case PROC_POLICY_RUSAGE_DISK:
348 case PROC_POLICY_RUSAGE_NETWORK:
349 case PROC_POLICY_RUSAGE_POWER:
350 return(ENOTSUP);
351 break;
352 default:
353 return(EINVAL);
354 case PROC_POLICY_RUSAGE_CPU:
355 break;
356 }
357
358 switch (action) {
359 case PROC_POLICY_ACTION_GET:
360 error = proc_get_task_ruse_cpu(proc->task, &cpuattr.ppattr_cpu_attr,
361 &cpuattr.ppattr_cpu_percentage,
362 &cpuattr.ppattr_cpu_attr_interval,
363 &cpuattr.ppattr_cpu_attr_deadline);
364 if (error == 0)
365 error = copyout((proc_policy_cpuusage_attr_t *)&cpuattr, (user_addr_t)attrp, sizeof(proc_policy_cpuusage_attr_t));
366 break;
367
368 case PROC_POLICY_ACTION_APPLY:
369 case PROC_POLICY_ACTION_SET:
370 error = copyin((user_addr_t)attrp, (proc_policy_cpuusage_attr_t *)&cpuattr, sizeof(proc_policy_cpuusage_attr_t));
371
372 if (error == 0) {
373 error = proc_set_task_ruse_cpu(proc->task, cpuattr.ppattr_cpu_attr,
374 cpuattr.ppattr_cpu_percentage,
375 cpuattr.ppattr_cpu_attr_interval,
376 cpuattr.ppattr_cpu_attr_deadline);
377 }
378 break;
379
380 case PROC_POLICY_ACTION_RESTORE:
381 error = proc_clear_task_ruse_cpu(proc->task);
382 break;
383
384 default:
385 error = EINVAL;
386 break;
387
388 }
389
390 return(error);
391 }
392
393 #if CONFIG_EMBEDDED
394 static int
395 handle_applifecycle(__unused int scope, int action, __unused int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid)
396 {
397
398 int error = 0;
399 int state = 0, oldstate = 0;
400 int noteval = 0;
401
402
403
404 switch(policy_subtype) {
405 case PROC_POLICY_APPLIFE_NONE:
406 error = 0;
407 break;
408
409 case PROC_POLICY_APPLIFE_STATE:
410 #if CONFIG_MACF
411 error = mac_proc_check_sched(current_proc(), proc);
412 if (error)
413 goto out;
414 #endif
415 switch (action) {
416 case PROC_POLICY_ACTION_GET :
417 state = proc_lf_getappstate(proc->task);
418 error = copyout((int *)&state, (user_addr_t)attrp, sizeof(int));
419 break;
420 case PROC_POLICY_ACTION_APPLY :
421 case PROC_POLICY_ACTION_SET :
422 error = copyin((user_addr_t)attrp, (int *)&state, sizeof(int));
423 if ((error == 0) && (state != TASK_APPSTATE_NONE)) {
424 oldstate = proc_lf_getappstate(proc->task);
425 error = proc_lf_setappstate(proc->task, state);
426 if (error == 0) {
427 switch (state) {
428 case TASK_APPSTATE_ACTIVE:
429 noteval = NOTE_APPACTIVE;
430 break;
431 case TASK_APPSTATE_BACKGROUND:
432 noteval = NOTE_APPBACKGROUND;
433 break;
434 case TASK_APPSTATE_NONUI:
435 noteval = NOTE_APPNONUI;
436 break;
437 case TASK_APPSTATE_INACTIVE:
438 noteval = NOTE_APPINACTIVE;
439 break;
440 }
441
442 proc_lock(proc);
443 proc_knote(proc, noteval);
444 proc_unlock(proc);
445 }
446 }
447 break;
448
449 default:
450 error = EINVAL;
451 break;
452 }
453 break;
454
455 case PROC_POLICY_APPLIFE_DEVSTATUS:
456 #if CONFIG_MACF
457 /* ToDo - this should be a generic check, since we could potentially hang other behaviours here. */
458 error = mac_proc_check_suspend_resume(current_proc(), MAC_PROC_CHECK_HIBERNATE);
459 if (error) {
460 error = EPERM;
461 goto out;
462 }
463 #endif
464 if (action == PROC_POLICY_ACTION_APPLY) {
465 /* Used as a freeze hint */
466 memorystatus_on_inactivity(-1);
467
468 /* in future use devicestatus for pid_socketshutdown() */
469 error = 0;
470 } else {
471 error = EINVAL;
472 }
473 break;
474
475 case PROC_POLICY_APPLIFE_PIDBIND:
476 #if CONFIG_MACF
477 error = mac_proc_check_suspend_resume(current_proc(), MAC_PROC_CHECK_PIDBIND);
478 if (error) {
479 error = EPERM;
480 goto out;
481 }
482 #endif
483 error = copyin((user_addr_t)attrp, (int *)&state, sizeof(int));
484 if (error != 0)
485 goto out;
486 if (action == PROC_POLICY_ACTION_APPLY) {
487 /* bind the thread in target_thread in current process to target_proc */
488 error = proc_lf_pidbind(current_task(), target_threadid, proc->task, state);
489 } else
490 error = EINVAL;
491 break;
492 default:
493 error = EINVAL;
494 break;
495 }
496
497 out:
498 return(error);
499 }
500 #endif /* CONFIG_EMBEDDED */
501
502
503 static int
504 handle_apptype(__unused int scope, int action, __unused int policy, int policy_subtype, __unused user_addr_t attrp, proc_t target_proc, __unused uint64_t target_threadid)
505 {
506 int error = 0;
507
508 switch(policy_subtype) {
509 #if !CONFIG_EMBEDDED
510 case PROC_POLICY_OSX_APPTYPE_TAL:
511 /* need to be super user to do this */
512 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
513 error = EPERM;
514 goto out;
515 }
516 break;
517 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
518 /* no special priv needed */
519 break;
520 #endif /* !CONFIG_EMBEDDED */
521 case PROC_POLICY_OSX_APPTYPE_NONE:
522 #if CONFIG_EMBEDDED
523 case PROC_POLICY_IOS_RESV1_APPTYPE:
524 case PROC_POLICY_IOS_APPLE_DAEMON:
525 case PROC_POLICY_IOS_APPTYPE:
526 case PROC_POLICY_IOS_NONUITYPE:
527 #endif /* CONFIG_EMBEDDED */
528 return(ENOTSUP);
529 break;
530 default:
531 return(EINVAL);
532 }
533
534 switch (action) {
535 case PROC_POLICY_ACTION_ENABLE:
536 /* reapply the app foreground/background policy */
537 error = proc_enable_task_apptype(target_proc->task, policy_subtype);
538 break;
539 case PROC_POLICY_ACTION_DISABLE:
540 /* remove the app foreground/background policy */
541 error = proc_disable_task_apptype(target_proc->task, policy_subtype);
542 break;
543 default:
544 error = EINVAL;
545 break;
546 }
547
548 #if !CONFIG_EMBEDDED
549 out:
550 #endif /* !CONFIG_EMBEDDED */
551 return(error);
552 }
553
554
555 int
556 proc_apply_resource_actions(void * bsdinfo, int type, int action)
557 {
558 proc_t p = (proc_t)bsdinfo;
559
560 switch(action) {
561 case PROC_POLICY_RSRCACT_THROTTLE:
562 /* no need to do anything */
563 break;
564
565 case PROC_POLICY_RSRCACT_SUSPEND:
566 task_suspend(p->task);
567 break;
568
569 case PROC_POLICY_RSRCACT_TERMINATE:
570 psignal(p, SIGKILL);
571 break;
572
573 case PROC_POLICY_RSRCACT_NOTIFY_KQ:
574 proc_lock(p);
575 proc_knote(p, NOTE_RESOURCEEND | (type & 0xff));
576 proc_unlock(p);
577 break;
578
579 case PROC_POLICY_RSRCACT_NOTIFY_EXC:
580 panic("shouldn't be applying exception notification to process!");
581 break;
582 }
583
584 return(0);
585 }
586
587
588 int
589 proc_restore_resource_actions(void * bsdinfo, __unused int type, int action)
590 {
591 proc_t p = (proc_t)bsdinfo;
592
593 switch(action) {
594 case PROC_POLICY_RSRCACT_THROTTLE:
595 case PROC_POLICY_RSRCACT_TERMINATE:
596 case PROC_POLICY_RSRCACT_NOTIFY_KQ:
597 case PROC_POLICY_RSRCACT_NOTIFY_EXC:
598 /* no need to do anything */
599 break;
600
601 case PROC_POLICY_RSRCACT_SUSPEND:
602 task_resume(p->task);
603 break;
604
605 }
606
607 return(0);
608 }
609