]>
Commit | Line | Data |
---|---|---|
6d2010ae | 1 | /* |
39037602 | 2 | * Copyright (c) 2005-2016 Apple Computer, Inc. All rights reserved. |
6d2010ae A |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
0a7de745 | 5 | * |
6d2010ae A |
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. | |
0a7de745 | 14 | * |
6d2010ae A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
6d2010ae A |
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. | |
0a7de745 | 25 | * |
6d2010ae A |
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> | |
5ba3f43e | 37 | #include <sys/priv.h> |
6d2010ae | 38 | #include <sys/proc_internal.h> |
39236c6e | 39 | #include <sys/proc.h> |
6d2010ae A |
40 | #include <sys/kauth.h> |
41 | #include <sys/unistd.h> | |
42 | #include <sys/buf.h> | |
43 | #include <sys/ioctl.h> | |
44 | #include <sys/vm.h> | |
45 | #include <sys/user.h> | |
46 | ||
6d2010ae A |
47 | #include <mach/machine.h> |
48 | #include <mach/mach_types.h> | |
49 | #include <mach/vm_param.h> | |
50 | #include <kern/task.h> | |
6d2010ae | 51 | #include <kern/assert.h> |
39037602 A |
52 | #include <kern/policy_internal.h> |
53 | ||
6d2010ae A |
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 | 72 | |
f427ee49 | 73 | #if !defined(XNU_TARGET_OS_OSX) |
5ba3f43e | 74 | #include <sys/kern_memorystatus.h> |
f427ee49 | 75 | #endif /* !defined(XNU_TARGET_OS_OSX) */ |
5ba3f43e A |
76 | |
77 | #if CONFIG_MACF | |
78 | #include <security/mac.h> | |
79 | #include <security/mac_framework.h> | |
80 | #endif /* CONFIG_MACF */ | |
81 | ||
39236c6e | 82 | static int handle_lowresource(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); |
39037602 | 83 | static int handle_cpuuse(int action, user_addr_t attrp, proc_t proc, uint64_t target_threadid); |
6d2010ae | 84 | static int handle_apptype(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); |
39236c6e | 85 | static int handle_boost(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); |
f427ee49 A |
86 | static int handle_no_smt(int scope, int action, proc_t target_proc, uint64_t target_threadid); |
87 | static int handle_tecs(int scope, int action, proc_t target_proc, uint64_t target_threadid); | |
6d2010ae A |
88 | |
89 | extern kern_return_t task_suspend(task_t); | |
90 | extern kern_return_t task_resume(task_t); | |
91 | ||
f427ee49 | 92 | #if !defined(XNU_TARGET_OS_OSX) |
5ba3f43e | 93 | static int handle_applifecycle(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid); |
f427ee49 | 94 | #endif /* !defined(XNU_TARGET_OS_OSX) */ |
316670eb | 95 | |
6d2010ae A |
96 | /***************************** process_policy ********************/ |
97 | ||
98 | /* | |
0a7de745 A |
99 | * int process_policy(int scope, int action, int policy, int policy_subtype, |
100 | * proc_policy_attribute_t * attrp, pid_t target_pid, | |
6d2010ae | 101 | * uint64_t target_threadid) |
0a7de745 | 102 | *{ int process_policy(int scope, int action, int policy, int policy_subtype, |
6d2010ae A |
103 | * user_addr_t attrp, pid_t target_pid, uint64_t target_threadid); } |
104 | */ | |
105 | ||
39236c6e | 106 | /* system call implementation */ |
6d2010ae | 107 | int |
316670eb | 108 | process_policy(__unused struct proc *p, struct process_policy_args * uap, __unused int32_t *retval) |
6d2010ae A |
109 | { |
110 | int error = 0; | |
111 | int scope = uap->scope; | |
112 | int policy = uap->policy; | |
113 | int action = uap->action; | |
114 | int policy_subtype = uap->policy_subtype; | |
115 | user_addr_t attrp = uap->attrp; | |
116 | pid_t target_pid = uap->target_pid; | |
117 | uint64_t target_threadid = uap->target_threadid; | |
316670eb | 118 | proc_t target_proc = PROC_NULL; |
f427ee49 | 119 | #if CONFIG_MACF || defined(XNU_TARGET_OS_OSX) |
6d2010ae | 120 | proc_t curp = current_proc(); |
5ba3f43e | 121 | #endif |
6d2010ae | 122 | kauth_cred_t my_cred; |
f427ee49 | 123 | #if !defined(XNU_TARGET_OS_OSX) |
5ba3f43e A |
124 | kauth_cred_t target_cred; |
125 | #endif | |
6d2010ae A |
126 | |
127 | if ((scope != PROC_POLICY_SCOPE_PROCESS) && (scope != PROC_POLICY_SCOPE_THREAD)) { | |
0a7de745 | 128 | return EINVAL; |
6d2010ae | 129 | } |
39236c6e | 130 | |
0a7de745 | 131 | if (target_pid == 0 || target_pid == proc_selfpid()) { |
39236c6e | 132 | target_proc = proc_self(); |
0a7de745 | 133 | } else { |
39236c6e | 134 | target_proc = proc_find(target_pid); |
0a7de745 | 135 | } |
39236c6e | 136 | |
0a7de745 A |
137 | if (target_proc == PROC_NULL) { |
138 | return ESRCH; | |
139 | } | |
6d2010ae | 140 | |
316670eb | 141 | my_cred = kauth_cred_get(); |
6d2010ae | 142 | |
f427ee49 | 143 | #if !defined(XNU_TARGET_OS_OSX) |
5ba3f43e A |
144 | target_cred = kauth_cred_proc_ref(target_proc); |
145 | ||
146 | if (!kauth_cred_issuser(my_cred) && kauth_cred_getruid(my_cred) && | |
147 | kauth_cred_getuid(my_cred) != kauth_cred_getuid(target_cred) && | |
148 | kauth_cred_getruid(my_cred) != kauth_cred_getuid(target_cred)) | |
149 | #else | |
0a7de745 | 150 | /* |
6d2010ae A |
151 | * Resoure starvation control can be used by unpriv resource owner but priv at the time of ownership claim. This is |
152 | * checked in low resource handle routine. So bypass the checks here. | |
153 | */ | |
0a7de745 A |
154 | if ((policy != PROC_POLICY_RESOURCE_STARVATION) && |
155 | (policy != PROC_POLICY_APPTYPE) && | |
156 | (!kauth_cred_issuser(my_cred) && curp != target_proc)) | |
5ba3f43e | 157 | #endif |
6d2010ae A |
158 | { |
159 | error = EPERM; | |
160 | goto out; | |
161 | } | |
162 | ||
163 | #if CONFIG_MACF | |
39236c6e | 164 | switch (policy) { |
0a7de745 A |
165 | case PROC_POLICY_BOOST: |
166 | case PROC_POLICY_RESOURCE_USAGE: | |
f427ee49 | 167 | #if !defined(XNU_TARGET_OS_OSX) |
0a7de745 A |
168 | case PROC_POLICY_APPTYPE: |
169 | case PROC_POLICY_APP_LIFECYCLE: | |
5ba3f43e | 170 | #endif |
0a7de745 A |
171 | /* These policies do their own appropriate mac checks */ |
172 | break; | |
173 | default: | |
174 | error = mac_proc_check_sched(curp, target_proc); | |
175 | if (error) { | |
176 | goto out; | |
177 | } | |
178 | break; | |
316670eb | 179 | } |
316670eb | 180 | #endif /* CONFIG_MACF */ |
6d2010ae | 181 | |
0a7de745 A |
182 | switch (policy) { |
183 | case PROC_POLICY_BACKGROUND: | |
184 | error = ENOTSUP; | |
185 | break; | |
186 | case PROC_POLICY_HARDWARE_ACCESS: | |
187 | error = ENOTSUP; | |
188 | break; | |
189 | case PROC_POLICY_RESOURCE_STARVATION: | |
190 | error = handle_lowresource(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); | |
191 | break; | |
192 | case PROC_POLICY_RESOURCE_USAGE: | |
193 | switch (policy_subtype) { | |
194 | case PROC_POLICY_RUSAGE_NONE: | |
195 | case PROC_POLICY_RUSAGE_WIREDMEM: | |
196 | case PROC_POLICY_RUSAGE_VIRTMEM: | |
197 | case PROC_POLICY_RUSAGE_DISK: | |
198 | case PROC_POLICY_RUSAGE_NETWORK: | |
199 | case PROC_POLICY_RUSAGE_POWER: | |
39236c6e | 200 | error = ENOTSUP; |
0a7de745 | 201 | goto out; |
6d2010ae A |
202 | default: |
203 | error = EINVAL; | |
0a7de745 A |
204 | goto out; |
205 | case PROC_POLICY_RUSAGE_CPU: | |
6d2010ae | 206 | break; |
0a7de745 A |
207 | } |
208 | ||
209 | error = handle_cpuuse(action, attrp, target_proc, target_threadid); | |
210 | break; | |
f427ee49 | 211 | #if !defined(XNU_TARGET_OS_OSX) |
0a7de745 A |
212 | case PROC_POLICY_APP_LIFECYCLE: |
213 | error = handle_applifecycle(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); | |
214 | break; | |
f427ee49 | 215 | #endif /* !defined(XNU_TARGET_OS_OSX) */ |
0a7de745 A |
216 | case PROC_POLICY_APPTYPE: |
217 | error = handle_apptype(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); | |
218 | break; | |
219 | case PROC_POLICY_BOOST: | |
220 | error = handle_boost(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); | |
221 | break; | |
f427ee49 A |
222 | case PROC_POLICY_NO_SMT: |
223 | error = handle_no_smt(scope, action, target_proc, target_threadid); | |
224 | break; | |
225 | case PROC_POLICY_TECS: | |
226 | error = handle_tecs(scope, action, target_proc, target_threadid); | |
227 | break; | |
0a7de745 A |
228 | default: |
229 | error = EINVAL; | |
230 | break; | |
6d2010ae A |
231 | } |
232 | ||
233 | out: | |
316670eb | 234 | proc_rele(target_proc); |
f427ee49 | 235 | #if !defined(XNU_TARGET_OS_OSX) |
0a7de745 | 236 | kauth_cred_unref(&target_cred); |
5ba3f43e | 237 | #endif |
0a7de745 | 238 | return error; |
6d2010ae A |
239 | } |
240 | ||
39236c6e A |
241 | static int |
242 | 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) | |
6d2010ae A |
243 | { |
244 | int error = 0; | |
245 | ||
0a7de745 A |
246 | switch (policy_subtype) { |
247 | case PROC_POLICY_RS_NONE: | |
248 | case PROC_POLICY_RS_VIRTUALMEM: | |
249 | break; | |
250 | default: | |
251 | return EINVAL; | |
6d2010ae | 252 | } |
0a7de745 A |
253 | |
254 | if (action == PROC_POLICY_ACTION_RESTORE) { | |
6d2010ae | 255 | error = proc_resetpcontrol(proc_pid(proc)); |
0a7de745 | 256 | } else { |
6d2010ae | 257 | error = EINVAL; |
0a7de745 | 258 | } |
6d2010ae | 259 | |
0a7de745 | 260 | return error; |
6d2010ae A |
261 | } |
262 | ||
263 | ||
0a7de745 | 264 | static int |
39037602 | 265 | handle_cpuuse(int action, user_addr_t attrp, proc_t proc, __unused uint64_t target_threadid) |
6d2010ae | 266 | { |
0a7de745 | 267 | proc_policy_cpuusage_attr_t cpuattr = { }; |
f427ee49 | 268 | #if CONFIG_MACF || defined(XNU_TARGET_OS_OSX) |
0a7de745 | 269 | proc_t curp = current_proc(); |
39236c6e | 270 | #endif |
0a7de745 A |
271 | Boolean privileged = FALSE; |
272 | Boolean canEnable = FALSE; | |
273 | uint64_t interval = -1ULL; | |
274 | int error = 0; | |
275 | uint8_t percentage; | |
6d2010ae | 276 | |
f427ee49 | 277 | #if defined(XNU_TARGET_OS_OSX) |
5ba3f43e A |
278 | /* On macOS, tasks can only set and clear their own CPU limits. */ |
279 | if ((action == PROC_POLICY_ACTION_APPLY || action == PROC_POLICY_ACTION_RESTORE) | |
0a7de745 A |
280 | && curp != proc) { |
281 | return EPERM; | |
5ba3f43e A |
282 | } |
283 | /* No privilege required on macOS. */ | |
284 | privileged = TRUE; | |
285 | #endif | |
286 | ||
39236c6e | 287 | #if CONFIG_MACF |
5ba3f43e A |
288 | /* Is caller privileged to set less-restrictive scheduling parameters? */ |
289 | if (!privileged) { | |
290 | privileged = (priv_check_cred(kauth_cred_get(), PRIV_PROC_CPUMON_OVERRIDE, 0) == 0); | |
291 | } | |
292 | canEnable = (privileged && action == PROC_POLICY_ACTION_ENABLE); | |
39037602 A |
293 | |
294 | if (!canEnable && curp != proc) { | |
5ba3f43e A |
295 | /* |
296 | * Can the current process change scheduling parameters for | |
297 | * the target process? | |
298 | */ | |
39037602 | 299 | error = mac_proc_check_sched(curp, proc); |
0a7de745 A |
300 | if (error) { |
301 | return error; | |
302 | } | |
39037602 | 303 | } |
39236c6e A |
304 | #endif |
305 | ||
6d2010ae | 306 | switch (action) { |
0a7de745 A |
307 | case PROC_POLICY_ACTION_GET: |
308 | error = proc_get_task_ruse_cpu(proc->task, &cpuattr.ppattr_cpu_attr, | |
309 | &percentage, | |
310 | &cpuattr.ppattr_cpu_attr_interval, | |
311 | &cpuattr.ppattr_cpu_attr_deadline); | |
312 | if (error == 0) { | |
313 | cpuattr.ppattr_cpu_percentage = percentage; | |
314 | cpuattr.ppattr_cpu_attr_interval /= NSEC_PER_SEC; | |
315 | error = copyout((proc_policy_cpuusage_attr_t *)&cpuattr, (user_addr_t)attrp, sizeof(proc_policy_cpuusage_attr_t)); | |
316 | } | |
317 | break; | |
318 | ||
319 | case PROC_POLICY_ACTION_APPLY: | |
320 | case PROC_POLICY_ACTION_SET: | |
321 | error = copyin((user_addr_t)attrp, (proc_policy_cpuusage_attr_t *)&cpuattr, sizeof(proc_policy_cpuusage_attr_t)); | |
322 | if (error != 0) { | |
323 | return error; | |
324 | } | |
6d2010ae | 325 | |
0a7de745 A |
326 | /* |
327 | * The process_policy API uses seconds as the units for the interval, | |
328 | * but the mach task policy SPI uses nanoseconds. Do the conversion, | |
329 | * but preserve -1 as it has special meaning. | |
330 | */ | |
331 | if (cpuattr.ppattr_cpu_attr_interval != -1ULL) { | |
332 | interval = cpuattr.ppattr_cpu_attr_interval * NSEC_PER_SEC; | |
333 | } else { | |
334 | interval = -1ULL; | |
335 | } | |
336 | ||
f427ee49 A |
337 | error = proc_set_task_ruse_cpu(proc->task, (uint16_t)cpuattr.ppattr_cpu_attr, |
338 | (uint8_t)MIN(cpuattr.ppattr_cpu_percentage, UINT8_MAX), | |
0a7de745 A |
339 | interval, |
340 | cpuattr.ppattr_cpu_attr_deadline, | |
341 | privileged); | |
342 | break; | |
343 | ||
344 | /* restore process to prior state */ | |
345 | case PROC_POLICY_ACTION_RESTORE: | |
346 | error = proc_clear_task_ruse_cpu(proc->task, privileged); | |
347 | break; | |
348 | ||
349 | /* re-enable suspended monitor */ | |
350 | case PROC_POLICY_ACTION_ENABLE: | |
351 | error = task_resume_cpumon(proc->task); | |
352 | break; | |
353 | ||
354 | case PROC_POLICY_ACTION_REMOVE: | |
355 | ||
356 | default: | |
357 | error = EINVAL; | |
358 | break; | |
6d2010ae | 359 | } |
0a7de745 A |
360 | |
361 | return error; | |
6d2010ae A |
362 | } |
363 | ||
f427ee49 | 364 | #if !defined(XNU_TARGET_OS_OSX) |
0a7de745 | 365 | static int |
5ba3f43e | 366 | handle_applifecycle(__unused int scope, |
0a7de745 A |
367 | int action, |
368 | __unused int policy, | |
369 | int policy_subtype, | |
370 | user_addr_t attrp, | |
371 | proc_t proc, | |
f427ee49 | 372 | __unused uint64_t target_threadid) |
5ba3f43e A |
373 | { |
374 | int error = 0; | |
375 | int state = 0; | |
376 | ||
0a7de745 A |
377 | switch (policy_subtype) { |
378 | case PROC_POLICY_APPLIFE_NONE: | |
379 | error = 0; | |
380 | break; | |
5ba3f43e | 381 | |
0a7de745 A |
382 | case PROC_POLICY_APPLIFE_STATE: |
383 | /* appstate is no longer supported */ | |
384 | error = ENOTSUP; | |
385 | break; | |
5ba3f43e | 386 | |
0a7de745 | 387 | case PROC_POLICY_APPLIFE_DEVSTATUS: |
5ba3f43e | 388 | #if CONFIG_MACF |
0a7de745 | 389 | /* ToDo - this should be a generic check, since we could potentially hang other behaviours here. */ |
f427ee49 | 390 | error = mac_proc_check_suspend_resume(proc, MAC_PROC_CHECK_HIBERNATE); |
0a7de745 A |
391 | if (error) { |
392 | error = EPERM; | |
393 | goto out; | |
394 | } | |
5ba3f43e A |
395 | #endif |
396 | #if CONFIG_MEMORYSTATUS | |
0a7de745 A |
397 | if (action == PROC_POLICY_ACTION_APPLY) { |
398 | /* Used as a freeze hint */ | |
399 | memorystatus_on_inactivity(proc); | |
400 | ||
401 | /* in future use devicestatus for pid_socketshutdown() */ | |
402 | error = 0; | |
403 | } else | |
5ba3f43e | 404 | #endif |
0a7de745 A |
405 | { |
406 | error = EINVAL; | |
407 | } | |
408 | break; | |
5ba3f43e | 409 | |
0a7de745 | 410 | case PROC_POLICY_APPLIFE_PIDBIND: |
5ba3f43e | 411 | #if CONFIG_MACF |
f427ee49 | 412 | error = mac_proc_check_suspend_resume(proc, MAC_PROC_CHECK_PIDBIND); |
0a7de745 A |
413 | if (error) { |
414 | error = EPERM; | |
415 | goto out; | |
416 | } | |
5ba3f43e | 417 | #endif |
0a7de745 A |
418 | error = copyin((user_addr_t)attrp, (int *)&state, sizeof(int)); |
419 | if (error != 0) { | |
420 | goto out; | |
421 | } | |
f427ee49 | 422 | #if CONFIG_TASKWATCH |
0a7de745 A |
423 | if (action == PROC_POLICY_ACTION_APPLY) { |
424 | /* bind the thread in target_thread in current process to target_proc */ | |
425 | error = proc_lf_pidbind(current_task(), target_threadid, proc->task, state); | |
f427ee49 A |
426 | } else |
427 | #endif /* CONFIG_TASKWATCH */ | |
428 | { | |
5ba3f43e | 429 | error = EINVAL; |
0a7de745 A |
430 | } |
431 | break; | |
432 | default: | |
433 | error = EINVAL; | |
434 | break; | |
5ba3f43e A |
435 | } |
436 | ||
437 | out: | |
0a7de745 | 438 | return error; |
5ba3f43e | 439 | } |
f427ee49 | 440 | #endif /* !defined(XNU_TARGET_OS_OSX) */ |
39236c6e A |
441 | |
442 | static int | |
443 | handle_apptype( int scope, | |
0a7de745 A |
444 | int action, |
445 | __unused int policy, | |
446 | int policy_subtype, | |
447 | __unused user_addr_t attrp, | |
448 | proc_t target_proc, | |
449 | __unused uint64_t target_threadid) | |
316670eb | 450 | { |
39236c6e A |
451 | int error = 0; |
452 | ||
0a7de745 A |
453 | if (scope != PROC_POLICY_SCOPE_PROCESS) { |
454 | return EINVAL; | |
455 | } | |
39236c6e A |
456 | |
457 | /* Temporary compatibility with old importance donation interface until libproc is moved to new boost calls */ | |
458 | switch (policy_subtype) { | |
0a7de745 A |
459 | case PROC_POLICY_IOS_DONATEIMP: |
460 | if (action != PROC_POLICY_ACTION_ENABLE) { | |
461 | return EINVAL; | |
462 | } | |
463 | if (target_proc != current_proc()) { | |
464 | return EINVAL; | |
465 | } | |
39236c6e | 466 | |
0a7de745 A |
467 | /* PROCESS ENABLE APPTYPE DONATEIMP */ |
468 | task_importance_mark_donor(target_proc->task, TRUE); | |
39236c6e | 469 | |
0a7de745 | 470 | return 0; |
39236c6e | 471 | |
0a7de745 A |
472 | case PROC_POLICY_IOS_HOLDIMP: |
473 | if (action != PROC_POLICY_ACTION_ENABLE) { | |
474 | return EINVAL; | |
475 | } | |
476 | if (target_proc != current_proc()) { | |
477 | return EINVAL; | |
478 | } | |
39236c6e | 479 | |
0a7de745 A |
480 | /* PROCESS ENABLE APPTYPE HOLDIMP */ |
481 | error = task_importance_hold_legacy_external_assertion(current_task(), 1); | |
39236c6e | 482 | |
0a7de745 | 483 | return error; |
39236c6e | 484 | |
0a7de745 A |
485 | case PROC_POLICY_IOS_DROPIMP: |
486 | if (action != PROC_POLICY_ACTION_ENABLE) { | |
487 | return EINVAL; | |
488 | } | |
489 | if (target_proc != current_proc()) { | |
490 | return EINVAL; | |
491 | } | |
39236c6e | 492 | |
0a7de745 A |
493 | /* PROCESS ENABLE APPTYPE DROPIMP */ |
494 | error = task_importance_drop_legacy_external_assertion(current_task(), 1); | |
39236c6e | 495 | |
0a7de745 A |
496 | return error; |
497 | ||
0a7de745 A |
498 | default: |
499 | return EINVAL; | |
39236c6e | 500 | } |
39236c6e A |
501 | } |
502 | ||
503 | static int | |
504 | handle_boost(int scope, | |
0a7de745 | 505 | int action, |
39236c6e | 506 | __unused int policy, |
0a7de745 | 507 | int policy_subtype, |
39236c6e | 508 | __unused user_addr_t attrp, |
0a7de745 | 509 | proc_t target_proc, |
39236c6e A |
510 | __unused uint64_t target_threadid) |
511 | { | |
316670eb | 512 | int error = 0; |
316670eb | 513 | |
39236c6e A |
514 | assert(policy == PROC_POLICY_BOOST); |
515 | ||
0a7de745 A |
516 | if (scope != PROC_POLICY_SCOPE_PROCESS) { |
517 | return EINVAL; | |
518 | } | |
519 | ||
520 | if (target_proc != current_proc()) { | |
521 | return EINVAL; | |
522 | } | |
523 | ||
524 | switch (policy_subtype) { | |
525 | case PROC_POLICY_IMP_IMPORTANT: | |
526 | if (task_is_importance_receiver_type(target_proc->task) == FALSE) { | |
527 | return EINVAL; | |
528 | } | |
529 | ||
530 | switch (action) { | |
531 | case PROC_POLICY_ACTION_HOLD: | |
532 | /* PROCESS HOLD BOOST IMPORTANT */ | |
533 | error = task_importance_hold_legacy_external_assertion(current_task(), 1); | |
316670eb | 534 | break; |
0a7de745 A |
535 | case PROC_POLICY_ACTION_DROP: |
536 | /* PROCESS DROP BOOST IMPORTANT */ | |
537 | error = task_importance_drop_legacy_external_assertion(current_task(), 1); | |
538 | break; | |
539 | default: | |
540 | error = (EINVAL); | |
541 | break; | |
542 | } | |
543 | break; | |
316670eb | 544 | |
0a7de745 | 545 | case PROC_POLICY_IMP_DONATION: |
316670eb | 546 | #if CONFIG_MACF |
0a7de745 A |
547 | error = mac_proc_check_sched(current_proc(), target_proc); |
548 | if (error) { | |
549 | return error; | |
550 | } | |
316670eb | 551 | #endif |
0a7de745 A |
552 | switch (action) { |
553 | case PROC_POLICY_ACTION_SET: | |
554 | /* PROCESS SET BOOST DONATION */ | |
555 | task_importance_mark_donor(target_proc->task, TRUE); | |
316670eb | 556 | break; |
316670eb | 557 | default: |
39236c6e A |
558 | error = (EINVAL); |
559 | break; | |
0a7de745 A |
560 | } |
561 | break; | |
562 | ||
563 | default: | |
564 | error = (EINVAL); | |
565 | break; | |
316670eb A |
566 | } |
567 | ||
0a7de745 | 568 | return error; |
316670eb | 569 | } |
316670eb | 570 | |
f427ee49 A |
571 | static int |
572 | handle_no_smt(int scope, int action, proc_t target_proc, uint64_t target_threadid) | |
573 | { | |
574 | extern void task_set_no_smt(task_t); | |
575 | ||
576 | if (action != PROC_POLICY_ACTION_APPLY) { | |
577 | return EINVAL; | |
578 | } | |
579 | ||
580 | if (scope == PROC_POLICY_SCOPE_PROCESS) { | |
581 | if (target_proc != current_proc()) { | |
582 | return EINVAL; | |
583 | } | |
584 | task_set_no_smt(TASK_NULL); | |
585 | } else if (scope == PROC_POLICY_SCOPE_THREAD) { | |
586 | if (target_threadid != thread_tid(current_thread())) { | |
587 | return EINVAL; | |
588 | } | |
589 | thread_set_no_smt(true); | |
590 | } else { | |
591 | return EINVAL; | |
592 | } | |
593 | ||
594 | return 0; | |
595 | } | |
596 | ||
597 | static int | |
598 | handle_tecs(int scope, int action, proc_t target_proc, uint64_t target_threadid) | |
599 | { | |
600 | if (action != PROC_POLICY_ACTION_APPLY) { | |
601 | return EINVAL; | |
602 | } | |
603 | ||
604 | if (scope == PROC_POLICY_SCOPE_PROCESS) { | |
605 | if (target_proc != current_proc()) { | |
606 | return EINVAL; | |
607 | } | |
608 | task_set_tecs(TASK_NULL); | |
609 | } else if (scope == PROC_POLICY_SCOPE_THREAD) { | |
610 | if (target_threadid != thread_tid(current_thread())) { | |
611 | return EINVAL; | |
612 | } | |
613 | if (machine_csv(CPUVN_CI)) { | |
614 | machine_tecs(current_thread()); | |
615 | } | |
616 | } else { | |
617 | return EINVAL; | |
618 | } | |
619 | ||
620 | return 0; | |
621 | } | |
6d2010ae | 622 | |
0a7de745 A |
623 | /* |
624 | * KPI to determine if a pid is currently backgrounded. | |
39236c6e A |
625 | * Returns ESRCH if pid cannot be found or has started exiting. |
626 | * Returns EINVAL if state is NULL. | |
627 | * Sets *state to 1 if pid is backgrounded, and 0 otherwise. | |
628 | */ | |
629 | int | |
630 | proc_pidbackgrounded(pid_t pid, uint32_t* state) | |
6d2010ae | 631 | { |
39236c6e | 632 | proc_t target_proc = PROC_NULL; |
6d2010ae | 633 | |
0a7de745 A |
634 | if (state == NULL) { |
635 | return EINVAL; | |
636 | } | |
6d2010ae | 637 | |
39236c6e A |
638 | target_proc = proc_find(pid); |
639 | ||
0a7de745 A |
640 | if (target_proc == PROC_NULL) { |
641 | return ESRCH; | |
642 | } | |
39236c6e | 643 | |
0a7de745 | 644 | if (proc_get_effective_task_policy(target_proc->task, TASK_POLICY_DARWIN_BG)) { |
39236c6e A |
645 | *state = 1; |
646 | } else { | |
647 | *state = 0; | |
6d2010ae | 648 | } |
6d2010ae | 649 | |
39236c6e | 650 | proc_rele(target_proc); |
0a7de745 | 651 | return 0; |
39236c6e | 652 | } |
316670eb | 653 | |
fe8ab488 A |
654 | /* |
655 | * Get the darwin background state of the originator. If the current | |
656 | * process app type is App, then it is the originator, else if it is | |
657 | * a Daemon, then creator of the Resource Accounting attribute of | |
658 | * the current thread voucher is the originator of the work. | |
659 | */ | |
660 | int | |
661 | proc_get_originatorbgstate(uint32_t *is_backgrounded) | |
662 | { | |
663 | uint32_t bgstate; | |
664 | proc_t p = current_proc(); | |
5ba3f43e | 665 | uint32_t flagsp = 0; |
fe8ab488 A |
666 | kern_return_t kr; |
667 | pid_t pid; | |
668 | int ret; | |
669 | thread_t thread = current_thread(); | |
670 | ||
671 | bgstate = proc_get_effective_thread_policy(thread, TASK_POLICY_DARWIN_BG); | |
0a7de745 | 672 | |
fe8ab488 A |
673 | /* If current thread or task backgrounded, return background */ |
674 | if (bgstate) { | |
675 | *is_backgrounded = 1; | |
676 | return 0; | |
677 | } | |
678 | ||
679 | /* Check if current process app type is App, then return foreground */ | |
680 | proc_get_darwinbgstate(p->task, &flagsp); | |
681 | if ((flagsp & PROC_FLAG_APPLICATION) == PROC_FLAG_APPLICATION) { | |
682 | *is_backgrounded = 0; | |
683 | return 0; | |
684 | } | |
685 | ||
686 | /* | |
687 | * Get the current voucher origin pid and it's bgstate.The pid | |
688 | * returned here might not be valid or may have been recycled. | |
689 | */ | |
690 | kr = thread_get_current_voucher_origin_pid(&pid); | |
691 | if (kr != KERN_SUCCESS) { | |
0a7de745 | 692 | if (kr == KERN_INVALID_TASK) { |
fe8ab488 | 693 | return ESRCH; |
0a7de745 | 694 | } else if (kr == KERN_INVALID_VALUE) { |
fe8ab488 | 695 | return ENOATTR; |
0a7de745 | 696 | } else { |
fe8ab488 | 697 | return EINVAL; |
0a7de745 | 698 | } |
fe8ab488 A |
699 | } |
700 | ||
701 | ret = proc_pidbackgrounded(pid, is_backgrounded); | |
702 | return ret; | |
703 | } | |
704 | ||
6d2010ae | 705 | int |
39236c6e | 706 | proc_apply_resource_actions(void * bsdinfo, __unused int type, int action) |
6d2010ae A |
707 | { |
708 | proc_t p = (proc_t)bsdinfo; | |
709 | ||
0a7de745 A |
710 | switch (action) { |
711 | case PROC_POLICY_RSRCACT_THROTTLE: | |
712 | /* no need to do anything */ | |
713 | break; | |
6d2010ae | 714 | |
0a7de745 A |
715 | case PROC_POLICY_RSRCACT_SUSPEND: |
716 | task_suspend(p->task); | |
717 | break; | |
6d2010ae | 718 | |
0a7de745 A |
719 | case PROC_POLICY_RSRCACT_TERMINATE: |
720 | psignal(p, SIGKILL); | |
721 | break; | |
6d2010ae | 722 | |
0a7de745 A |
723 | case PROC_POLICY_RSRCACT_NOTIFY_KQ: |
724 | /* not implemented */ | |
725 | break; | |
726 | ||
727 | case PROC_POLICY_RSRCACT_NOTIFY_EXC: | |
728 | panic("shouldn't be applying exception notification to process!"); | |
729 | break; | |
6d2010ae A |
730 | } |
731 | ||
0a7de745 | 732 | return 0; |
6d2010ae A |
733 | } |
734 | ||
6d2010ae A |
735 | int |
736 | proc_restore_resource_actions(void * bsdinfo, __unused int type, int action) | |
737 | { | |
738 | proc_t p = (proc_t)bsdinfo; | |
739 | ||
0a7de745 A |
740 | switch (action) { |
741 | case PROC_POLICY_RSRCACT_THROTTLE: | |
742 | case PROC_POLICY_RSRCACT_TERMINATE: | |
743 | case PROC_POLICY_RSRCACT_NOTIFY_KQ: | |
744 | case PROC_POLICY_RSRCACT_NOTIFY_EXC: | |
745 | /* no need to do anything */ | |
746 | break; | |
747 | ||
748 | case PROC_POLICY_RSRCACT_SUSPEND: | |
749 | task_resume(p->task); | |
750 | break; | |
6d2010ae A |
751 | } |
752 | ||
0a7de745 | 753 | return 0; |
6d2010ae | 754 | } |