]>
Commit | Line | Data |
---|---|---|
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> | |
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 | ||
73 | static int handle_background(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); | |
74 | static int handle_hwaccess(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); | |
75 | static int handle_lowresrouce(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); | |
76 | static int handle_resourceuse(int scope, int action, int policy, int policy_subtype, 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 | ||
79 | extern kern_return_t task_suspend(task_t); | |
80 | extern kern_return_t task_resume(task_t); | |
81 | ||
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 | ||
92 | /* system call implementaion */ | |
93 | int | |
94 | process_policy(struct proc *p, struct process_policy_args * uap, __unused int32_t *retval) | |
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; | |
104 | proc_t proc = PROC_NULL; | |
105 | proc_t curp = current_proc(); | |
106 | kauth_cred_t my_cred; | |
107 | #if CONFIG_EMBEDDED | |
108 | kauth_cred_t target_cred; | |
109 | #endif | |
110 | ||
111 | if ((scope != PROC_POLICY_SCOPE_PROCESS) && (scope != PROC_POLICY_SCOPE_THREAD)) { | |
112 | return(EINVAL); | |
113 | } | |
114 | proc = proc_find(target_pid); | |
115 | if (proc == PROC_NULL) { | |
116 | return(EINVAL); | |
117 | } | |
118 | ||
119 | my_cred = kauth_cred_proc_ref(curp); | |
120 | ||
121 | #if CONFIG_EMBEDDED | |
122 | target_cred = kauth_cred_proc_ref(proc); | |
123 | ||
124 | if (suser(my_cred, NULL) && kauth_cred_getruid(my_cred) && | |
125 | kauth_cred_getuid(my_cred) != kauth_cred_getuid(target_cred) && | |
126 | kauth_cred_getruid(my_cred) != kauth_cred_getuid(target_cred)) | |
127 | #else | |
128 | /* | |
129 | * Resoure starvation control can be used by unpriv resource owner but priv at the time of ownership claim. This is | |
130 | * checked in low resource handle routine. So bypass the checks here. | |
131 | */ | |
132 | if ((policy != PROC_POLICY_RESOURCE_STARVATION) && | |
133 | (policy != PROC_POLICY_APPTYPE) && | |
134 | (suser(my_cred, NULL) && curp != p)) | |
135 | #endif | |
136 | { | |
137 | error = EPERM; | |
138 | goto out; | |
139 | } | |
140 | ||
141 | #if CONFIG_MACF | |
142 | error = mac_proc_check_sched(curp, p); | |
143 | if (error) | |
144 | goto out; | |
145 | #endif | |
146 | ||
147 | ||
148 | switch(policy) { | |
149 | case PROC_POLICY_BACKGROUND: | |
150 | error = handle_background(scope, action, policy, policy_subtype, attrp, proc, target_threadid); | |
151 | break; | |
152 | case PROC_POLICY_HARDWARE_ACCESS: | |
153 | error = handle_hwaccess(scope, action, policy, policy_subtype, attrp, proc, target_threadid); | |
154 | break; | |
155 | case PROC_POLICY_RESOURCE_STARVATION: | |
156 | error = handle_lowresrouce(scope, action, policy, policy_subtype, attrp, proc, target_threadid); | |
157 | break; | |
158 | case PROC_POLICY_RESOURCE_USAGE: | |
159 | error = handle_resourceuse(scope, action, policy, policy_subtype, attrp, proc, target_threadid); | |
160 | break; | |
161 | case PROC_POLICY_APPTYPE: | |
162 | error = handle_apptype(scope, action, policy, policy_subtype, attrp, proc, target_threadid); | |
163 | break; | |
164 | default: | |
165 | error = EINVAL; | |
166 | break; | |
167 | } | |
168 | ||
169 | out: | |
170 | proc_rele(proc); | |
171 | kauth_cred_unref(&my_cred); | |
172 | #if CONFIG_EMBEDDED | |
173 | kauth_cred_unref(&target_cred); | |
174 | #endif | |
175 | return(error); | |
176 | } | |
177 | ||
178 | ||
179 | /* darwin background handling code */ | |
180 | static int | |
181 | handle_background(int scope, int action, __unused int policy, __unused int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid) | |
182 | { | |
183 | int intval, error = 0; | |
184 | ||
185 | ||
186 | switch (action) { | |
187 | case PROC_POLICY_ACTION_GET: | |
188 | if (scope == PROC_POLICY_SCOPE_PROCESS) { | |
189 | intval = proc_get_task_bg_policy(proc->task); | |
190 | } else { | |
191 | /* thread scope */ | |
192 | intval = proc_get_thread_bg_policy(proc->task, target_threadid); | |
193 | } | |
194 | error = copyout((int *)&intval, (user_addr_t)attrp, sizeof(int)); | |
195 | break; | |
196 | ||
197 | case PROC_POLICY_ACTION_SET: | |
198 | error = copyin((user_addr_t)attrp, (int *)&intval, sizeof(int)); | |
199 | if (error != 0) | |
200 | goto out; | |
201 | if (intval > PROC_POLICY_BG_ALL) { | |
202 | error = EINVAL; | |
203 | goto out; | |
204 | } | |
205 | if (scope == PROC_POLICY_SCOPE_PROCESS) { | |
206 | error = proc_set_bgtaskpolicy(proc->task, intval); | |
207 | } else { | |
208 | /* thread scope */ | |
209 | error = proc_set_bgthreadpolicy(proc->task, target_threadid, intval); | |
210 | } | |
211 | break; | |
212 | ||
213 | case PROC_POLICY_ACTION_ADD: | |
214 | error = copyin((user_addr_t)attrp, (int *)&intval, sizeof(int)); | |
215 | if (error != 0) | |
216 | goto out; | |
217 | if (intval > PROC_POLICY_BG_ALL) { | |
218 | error = EINVAL; | |
219 | goto out; | |
220 | } | |
221 | if (scope == PROC_POLICY_SCOPE_PROCESS) { | |
222 | error = proc_add_bgtaskpolicy(proc->task, intval); | |
223 | } else { | |
224 | /* thread scope */ | |
225 | error = proc_add_bgthreadpolicy(proc->task, target_threadid, intval); | |
226 | } | |
227 | break; | |
228 | ||
229 | case PROC_POLICY_ACTION_REMOVE: | |
230 | error = copyin((user_addr_t)attrp, (int *)&intval, sizeof(int)); | |
231 | if (error != 0) | |
232 | goto out; | |
233 | if (intval > PROC_POLICY_BG_ALL) { | |
234 | error = EINVAL; | |
235 | goto out; | |
236 | } | |
237 | if (scope == PROC_POLICY_SCOPE_PROCESS) { | |
238 | error = proc_remove_bgtaskpolicy(proc->task, intval); | |
239 | } else { | |
240 | /* thread scope */ | |
241 | error = proc_remove_bgthreadpolicy(proc->task, target_threadid, intval); | |
242 | } | |
243 | break; | |
244 | ||
245 | case PROC_POLICY_ACTION_APPLY: | |
246 | if (scope == PROC_POLICY_SCOPE_PROCESS) { | |
247 | error = proc_apply_bgtaskpolicy(proc->task); | |
248 | } else { | |
249 | /* thread scope */ | |
250 | error = proc_apply_bgthreadpolicy(proc->task, target_threadid); | |
251 | } | |
252 | break; | |
253 | ||
254 | case PROC_POLICY_ACTION_RESTORE: | |
255 | if (scope == PROC_POLICY_SCOPE_PROCESS) { | |
256 | error = proc_restore_bgtaskpolicy(proc->task); | |
257 | } else { | |
258 | /* thread scope */ | |
259 | error = proc_restore_bgthreadpolicy(proc->task, target_threadid); | |
260 | } | |
261 | break; | |
262 | ||
263 | case PROC_POLICY_ACTION_DENYINHERIT: | |
264 | error = proc_denyinherit_policy(proc->task); | |
265 | break; | |
266 | ||
267 | case PROC_POLICY_ACTION_DENYSELFSET: | |
268 | error = proc_denyselfset_policy(proc->task); | |
269 | break; | |
270 | ||
271 | default: | |
272 | return(EINVAL); | |
273 | } | |
274 | ||
275 | out: | |
276 | return(error); | |
277 | } | |
278 | ||
279 | static int | |
280 | 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) | |
281 | { | |
282 | switch(policy_subtype) { | |
283 | case PROC_POLICY_HWACCESS_NONE: | |
284 | case PROC_POLICY_HWACCESS_DISK: | |
285 | case PROC_POLICY_HWACCESS_GPU: | |
286 | case PROC_POLICY_HWACCESS_NETWORK: | |
287 | case PROC_POLICY_HWACCESS_CPU: | |
288 | break; | |
289 | default: | |
290 | return(EINVAL); | |
291 | } | |
292 | return(0); | |
293 | } | |
294 | ||
295 | static int | |
296 | 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) | |
297 | { | |
298 | int error = 0; | |
299 | ||
300 | switch(policy_subtype) { | |
301 | case PROC_POLICY_RS_NONE: | |
302 | case PROC_POLICY_RS_VIRTUALMEM: | |
303 | break; | |
304 | default: | |
305 | return(EINVAL); | |
306 | } | |
307 | ||
308 | if (action == PROC_POLICY_ACTION_RESTORE) | |
309 | error = proc_resetpcontrol(proc_pid(proc)); | |
310 | else | |
311 | error = EINVAL; | |
312 | ||
313 | return(error); | |
314 | } | |
315 | ||
316 | ||
317 | static int | |
318 | 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) | |
319 | { | |
320 | proc_policy_cpuusage_attr_t cpuattr; | |
321 | int error = 0; | |
322 | ||
323 | switch(policy_subtype) { | |
324 | case PROC_POLICY_RUSAGE_NONE: | |
325 | case PROC_POLICY_RUSAGE_WIREDMEM: | |
326 | case PROC_POLICY_RUSAGE_VIRTMEM: | |
327 | case PROC_POLICY_RUSAGE_DISK: | |
328 | case PROC_POLICY_RUSAGE_NETWORK: | |
329 | case PROC_POLICY_RUSAGE_POWER: | |
330 | return(ENOTSUP); | |
331 | break; | |
332 | default: | |
333 | return(EINVAL); | |
334 | case PROC_POLICY_RUSAGE_CPU: | |
335 | break; | |
336 | } | |
337 | ||
338 | switch (action) { | |
339 | case PROC_POLICY_ACTION_GET: | |
340 | error = proc_get_task_ruse_cpu(proc->task, &cpuattr.ppattr_cpu_attr, | |
341 | &cpuattr.ppattr_cpu_percentage, | |
342 | &cpuattr.ppattr_cpu_attr_interval, | |
343 | &cpuattr.ppattr_cpu_attr_deadline); | |
344 | if (error == 0) | |
345 | error = copyout((proc_policy_cpuusage_attr_t *)&cpuattr, (user_addr_t)attrp, sizeof(proc_policy_cpuusage_attr_t)); | |
346 | break; | |
347 | ||
348 | case PROC_POLICY_ACTION_APPLY: | |
349 | case PROC_POLICY_ACTION_SET: | |
350 | error = copyin((user_addr_t)attrp, (proc_policy_cpuusage_attr_t *)&cpuattr, sizeof(proc_policy_cpuusage_attr_t)); | |
351 | ||
352 | if (error == 0) { | |
353 | error = proc_set_task_ruse_cpu(proc->task, cpuattr.ppattr_cpu_attr, | |
354 | cpuattr.ppattr_cpu_percentage, | |
355 | cpuattr.ppattr_cpu_attr_interval, | |
356 | cpuattr.ppattr_cpu_attr_deadline); | |
357 | } | |
358 | default: | |
359 | error = EINVAL; | |
360 | break; | |
361 | ||
362 | } | |
363 | ||
364 | return(error); | |
365 | } | |
366 | ||
367 | ||
368 | static int | |
369 | handle_apptype(__unused int scope, int action, __unused int policy, int policy_subtype, __unused user_addr_t attrp, proc_t proc, __unused uint64_t target_threadid) | |
370 | { | |
371 | int error = 0; | |
372 | ||
373 | switch(policy_subtype) { | |
374 | case PROC_POLICY_OSX_APPTYPE_TAL: | |
375 | /* need to be super user to do this */ | |
376 | if (kauth_cred_issuser(kauth_cred_get()) == 0) { | |
377 | error = EPERM; | |
378 | goto out; | |
379 | } | |
380 | break; | |
381 | case PROC_POLICY_OSX_APPTYPE_DASHCLIENT: | |
382 | /* no special priv needed */ | |
383 | break; | |
384 | case PROC_POLICY_OSX_APPTYPE_NONE: | |
385 | case PROC_POLICY_IOS_APPTYPE: | |
386 | case PROC_POLICY_IOS_NONUITYPE: | |
387 | return(ENOTSUP); | |
388 | break; | |
389 | default: | |
390 | return(EINVAL); | |
391 | } | |
392 | ||
393 | switch (action) { | |
394 | case PROC_POLICY_ACTION_ENABLE: | |
395 | /* reapply the app foreground/background policy */ | |
396 | error = proc_enable_task_apptype(proc->task, policy_subtype); | |
397 | break; | |
398 | case PROC_POLICY_ACTION_DISABLE: | |
399 | /* remove the app foreground/background policy */ | |
400 | error = proc_disable_task_apptype(proc->task, policy_subtype); | |
401 | break; | |
402 | default: | |
403 | error = EINVAL; | |
404 | break; | |
405 | } | |
406 | ||
407 | out: | |
408 | return(error); | |
409 | } | |
410 | ||
411 | int | |
412 | proc_apply_resource_actions(void * bsdinfo, int type, int action) | |
413 | { | |
414 | proc_t p = (proc_t)bsdinfo; | |
415 | ||
416 | switch(action) { | |
417 | case PROC_POLICY_RSRCACT_THROTTLE: | |
418 | /* no need to do anything */ | |
419 | break; | |
420 | ||
421 | case PROC_POLICY_RSRCACT_SUSPEND: | |
422 | task_suspend(p->task); | |
423 | break; | |
424 | ||
425 | case PROC_POLICY_RSRCACT_TERMINATE: | |
426 | psignal(p, SIGKILL); | |
427 | break; | |
428 | ||
429 | case PROC_POLICY_RSRCACT_NOTIFY: | |
430 | proc_lock(p); | |
431 | proc_knote(p, NOTE_RESOURCEEND | (type & 0xff)); | |
432 | proc_unlock(p); | |
433 | break; | |
434 | } | |
435 | ||
436 | return(0); | |
437 | } | |
438 | ||
439 | ||
440 | int | |
441 | proc_restore_resource_actions(void * bsdinfo, __unused int type, int action) | |
442 | { | |
443 | proc_t p = (proc_t)bsdinfo; | |
444 | ||
445 | switch(action) { | |
446 | case PROC_POLICY_RSRCACT_THROTTLE: | |
447 | case PROC_POLICY_RSRCACT_TERMINATE: | |
448 | case PROC_POLICY_RSRCACT_NOTIFY: | |
449 | /* no need to do anything */ | |
450 | break; | |
451 | ||
452 | case PROC_POLICY_RSRCACT_SUSPEND: | |
453 | task_resume(p->task); | |
454 | break; | |
455 | ||
456 | } | |
457 | ||
458 | return(0); | |
459 | } | |
460 |