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/priv.h> |
38 | #include <sys/proc_internal.h> |
39 | #include <sys/proc.h> |
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 | |
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/assert.h> |
52 | #include <kern/policy_internal.h> |
53 | |
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 | #if !defined(XNU_TARGET_OS_OSX) |
74 | #include <sys/kern_memorystatus.h> |
75 | #endif /* !defined(XNU_TARGET_OS_OSX) */ |
76 | |
77 | #if CONFIG_MACF |
78 | #include <security/mac.h> |
79 | #include <security/mac_framework.h> |
80 | #endif /* CONFIG_MACF */ |
81 | |
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); |
83 | static int handle_cpuuse(int action, user_addr_t attrp, proc_t proc, uint64_t target_threadid); |
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); |
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); |
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); |
88 | |
89 | extern kern_return_t task_suspend(task_t); |
90 | extern kern_return_t task_resume(task_t); |
91 | |
92 | #if !defined(XNU_TARGET_OS_OSX) |
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); |
94 | #endif /* !defined(XNU_TARGET_OS_OSX) */ |
95 | |
96 | /***************************** process_policy ********************/ |
97 | |
98 | /* |
99 | * int process_policy(int scope, int action, int policy, int policy_subtype, |
100 | * proc_policy_attribute_t * attrp, pid_t target_pid, |
101 | * uint64_t target_threadid) |
102 | *{ int process_policy(int scope, int action, int policy, int policy_subtype, |
103 | * user_addr_t attrp, pid_t target_pid, uint64_t target_threadid); } |
104 | */ |
105 | |
106 | /* system call implementation */ |
107 | int |
108 | process_policy(__unused struct proc *p, struct process_policy_args * uap, __unused int32_t *retval) |
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; |
118 | proc_t target_proc = PROC_NULL; |
119 | #if CONFIG_MACF || defined(XNU_TARGET_OS_OSX) |
120 | proc_t curp = current_proc(); |
121 | #endif |
122 | kauth_cred_t my_cred; |
123 | #if !defined(XNU_TARGET_OS_OSX) |
124 | kauth_cred_t target_cred; |
125 | #endif |
126 | |
127 | if ((scope != PROC_POLICY_SCOPE_PROCESS) && (scope != PROC_POLICY_SCOPE_THREAD)) { |
128 | return EINVAL; |
129 | } |
130 | |
131 | if (target_pid == 0 || target_pid == proc_selfpid()) { |
132 | target_proc = proc_self(); |
133 | } else { |
134 | target_proc = proc_find(pid: target_pid); |
135 | } |
136 | |
137 | if (target_proc == PROC_NULL) { |
138 | return ESRCH; |
139 | } |
140 | |
141 | my_cred = kauth_cred_get(); |
142 | |
143 | #if !defined(XNU_TARGET_OS_OSX) |
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 |
150 | /* |
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 | */ |
154 | if ((policy != PROC_POLICY_RESOURCE_STARVATION) && |
155 | (policy != PROC_POLICY_APPTYPE) && |
156 | (!kauth_cred_issuser(cred: my_cred) && curp != target_proc)) |
157 | #endif |
158 | { |
159 | error = EPERM; |
160 | goto out; |
161 | } |
162 | |
163 | #if CONFIG_MACF |
164 | switch (policy) { |
165 | case PROC_POLICY_BOOST: |
166 | case PROC_POLICY_RESOURCE_USAGE: |
167 | #if !defined(XNU_TARGET_OS_OSX) |
168 | case PROC_POLICY_APPTYPE: |
169 | case PROC_POLICY_APP_LIFECYCLE: |
170 | #endif |
171 | /* These policies do their own appropriate mac checks */ |
172 | break; |
173 | default: |
174 | error = mac_proc_check_sched(proc: curp, proc2: target_proc); |
175 | if (error) { |
176 | goto out; |
177 | } |
178 | break; |
179 | } |
180 | #endif /* CONFIG_MACF */ |
181 | |
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, proc: 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: |
200 | error = ENOTSUP; |
201 | goto out; |
202 | default: |
203 | error = EINVAL; |
204 | goto out; |
205 | case PROC_POLICY_RUSAGE_CPU: |
206 | break; |
207 | } |
208 | |
209 | error = handle_cpuuse(action, attrp, proc: target_proc, target_threadid); |
210 | break; |
211 | #if !defined(XNU_TARGET_OS_OSX) |
212 | case PROC_POLICY_APP_LIFECYCLE: |
213 | error = handle_applifecycle(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid); |
214 | break; |
215 | #endif /* !defined(XNU_TARGET_OS_OSX) */ |
216 | case PROC_POLICY_APPTYPE: |
217 | error = handle_apptype(scope, action, policy, policy_subtype, attrp, proc: target_proc, target_threadid); |
218 | break; |
219 | case PROC_POLICY_BOOST: |
220 | error = handle_boost(scope, action, policy, policy_subtype, attrp, proc: target_proc, target_threadid); |
221 | break; |
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; |
228 | default: |
229 | error = EINVAL; |
230 | break; |
231 | } |
232 | |
233 | out: |
234 | proc_rele(p: target_proc); |
235 | #if !defined(XNU_TARGET_OS_OSX) |
236 | kauth_cred_unref(&target_cred); |
237 | #endif |
238 | return error; |
239 | } |
240 | |
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) |
243 | { |
244 | int error = 0; |
245 | |
246 | switch (policy_subtype) { |
247 | case PROC_POLICY_RS_NONE: |
248 | case PROC_POLICY_RS_VIRTUALMEM: |
249 | break; |
250 | default: |
251 | return EINVAL; |
252 | } |
253 | |
254 | if (action == PROC_POLICY_ACTION_RESTORE) { |
255 | error = proc_resetpcontrol(pid: proc_pid(proc)); |
256 | } else { |
257 | error = EINVAL; |
258 | } |
259 | |
260 | return error; |
261 | } |
262 | |
263 | |
264 | static int |
265 | handle_cpuuse(int action, user_addr_t attrp, proc_t proc, __unused uint64_t target_threadid) |
266 | { |
267 | proc_policy_cpuusage_attr_t cpuattr = { }; |
268 | #if CONFIG_MACF || defined(XNU_TARGET_OS_OSX) |
269 | proc_t curp = current_proc(); |
270 | #endif |
271 | Boolean privileged = FALSE; |
272 | Boolean canEnable = FALSE; |
273 | uint64_t interval = -1ULL; |
274 | int error = 0; |
275 | uint8_t percentage; |
276 | |
277 | #if defined(XNU_TARGET_OS_OSX) |
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) |
280 | && curp != proc) { |
281 | return EPERM; |
282 | } |
283 | /* No privilege required on macOS. */ |
284 | privileged = TRUE; |
285 | #endif |
286 | |
287 | #if CONFIG_MACF |
288 | /* Is caller privileged to set less-restrictive scheduling parameters? */ |
289 | if (!privileged) { |
290 | privileged = (priv_check_cred(cred: kauth_cred_get(), PRIV_PROC_CPUMON_OVERRIDE, flags: 0) == 0); |
291 | } |
292 | canEnable = (privileged && action == PROC_POLICY_ACTION_ENABLE); |
293 | |
294 | if (!canEnable && curp != proc) { |
295 | /* |
296 | * Can the current process change scheduling parameters for |
297 | * the target process? |
298 | */ |
299 | error = mac_proc_check_sched(proc: curp, proc2: proc); |
300 | if (error) { |
301 | return error; |
302 | } |
303 | } |
304 | #endif |
305 | |
306 | switch (action) { |
307 | case PROC_POLICY_ACTION_GET: |
308 | error = proc_get_task_ruse_cpu(task: proc_task(proc), policyp: &cpuattr.ppattr_cpu_attr, |
309 | percentagep: &percentage, |
310 | intervalp: &cpuattr.ppattr_cpu_attr_interval, |
311 | deadlinep: &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 | } |
325 | |
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 | |
337 | error = proc_set_task_ruse_cpu(task: proc_task(proc), policy: (uint16_t)cpuattr.ppattr_cpu_attr, |
338 | percentage: (uint8_t)MIN(cpuattr.ppattr_cpu_percentage, UINT8_MAX), |
339 | interval, |
340 | deadline: cpuattr.ppattr_cpu_attr_deadline, |
341 | cpumon_entitled: privileged); |
342 | break; |
343 | |
344 | /* restore process to prior state */ |
345 | case PROC_POLICY_ACTION_RESTORE: |
346 | error = proc_clear_task_ruse_cpu(task: proc_task(proc), cpumon_entitled: privileged); |
347 | break; |
348 | |
349 | /* re-enable suspended monitor */ |
350 | case PROC_POLICY_ACTION_ENABLE: |
351 | error = task_resume_cpumon(task: proc_task(proc)); |
352 | break; |
353 | |
354 | case PROC_POLICY_ACTION_REMOVE: |
355 | |
356 | default: |
357 | error = EINVAL; |
358 | break; |
359 | } |
360 | |
361 | return error; |
362 | } |
363 | |
364 | #if !defined(XNU_TARGET_OS_OSX) |
365 | static int |
366 | handle_applifecycle(__unused int scope, |
367 | int action, |
368 | __unused int policy, |
369 | int policy_subtype, |
370 | user_addr_t attrp, |
371 | proc_t proc, |
372 | __unused uint64_t target_threadid) |
373 | { |
374 | int error = 0; |
375 | int state = 0; |
376 | |
377 | switch (policy_subtype) { |
378 | case PROC_POLICY_APPLIFE_NONE: |
379 | error = 0; |
380 | break; |
381 | |
382 | case PROC_POLICY_APPLIFE_STATE: |
383 | /* appstate is no longer supported */ |
384 | error = ENOTSUP; |
385 | break; |
386 | |
387 | case PROC_POLICY_APPLIFE_DEVSTATUS: |
388 | #if CONFIG_MACF |
389 | /* ToDo - this should be a generic check, since we could potentially hang other behaviours here. */ |
390 | error = mac_proc_check_suspend_resume(proc, MAC_PROC_CHECK_HIBERNATE); |
391 | if (error) { |
392 | error = EPERM; |
393 | goto out; |
394 | } |
395 | #endif |
396 | #if CONFIG_MEMORYSTATUS |
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 |
404 | #endif |
405 | { |
406 | error = EINVAL; |
407 | } |
408 | break; |
409 | |
410 | case PROC_POLICY_APPLIFE_PIDBIND: |
411 | #if CONFIG_MACF |
412 | error = mac_proc_check_suspend_resume(proc, MAC_PROC_CHECK_PIDBIND); |
413 | if (error) { |
414 | error = EPERM; |
415 | goto out; |
416 | } |
417 | #endif |
418 | error = copyin((user_addr_t)attrp, (int *)&state, sizeof(int)); |
419 | if (error != 0) { |
420 | goto out; |
421 | } |
422 | #if CONFIG_TASKWATCH |
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(proc), state); |
426 | } else |
427 | #endif /* CONFIG_TASKWATCH */ |
428 | { |
429 | error = EINVAL; |
430 | } |
431 | break; |
432 | default: |
433 | error = EINVAL; |
434 | break; |
435 | } |
436 | |
437 | out: |
438 | return error; |
439 | } |
440 | #endif /* !defined(XNU_TARGET_OS_OSX) */ |
441 | |
442 | static int |
443 | handle_apptype( int scope, |
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) |
450 | { |
451 | int error = 0; |
452 | |
453 | if (scope != PROC_POLICY_SCOPE_PROCESS) { |
454 | return EINVAL; |
455 | } |
456 | |
457 | /* Temporary compatibility with old importance donation interface until libproc is moved to new boost calls */ |
458 | switch (policy_subtype) { |
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 | } |
466 | |
467 | /* PROCESS ENABLE APPTYPE DONATEIMP */ |
468 | task_importance_mark_donor(task: proc_task(target_proc), TRUE); |
469 | |
470 | return 0; |
471 | |
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 | } |
479 | |
480 | /* PROCESS ENABLE APPTYPE HOLDIMP */ |
481 | error = task_importance_hold_legacy_external_assertion(target_task: current_task(), count: 1); |
482 | |
483 | return error; |
484 | |
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 | } |
492 | |
493 | /* PROCESS ENABLE APPTYPE DROPIMP */ |
494 | error = task_importance_drop_legacy_external_assertion(target_task: current_task(), count: 1); |
495 | |
496 | return error; |
497 | |
498 | default: |
499 | return EINVAL; |
500 | } |
501 | } |
502 | |
503 | static int |
504 | handle_boost(int scope, |
505 | int action, |
506 | __unused int policy, |
507 | int policy_subtype, |
508 | __unused user_addr_t attrp, |
509 | proc_t target_proc, |
510 | __unused uint64_t target_threadid) |
511 | { |
512 | int error = 0; |
513 | |
514 | assert(policy == PROC_POLICY_BOOST); |
515 | |
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(task: proc_task(target_proc)) == 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(target_task: current_task(), count: 1); |
534 | break; |
535 | case PROC_POLICY_ACTION_DROP: |
536 | /* PROCESS DROP BOOST IMPORTANT */ |
537 | error = task_importance_drop_legacy_external_assertion(target_task: current_task(), count: 1); |
538 | break; |
539 | default: |
540 | error = (EINVAL); |
541 | break; |
542 | } |
543 | break; |
544 | |
545 | case PROC_POLICY_IMP_DONATION: |
546 | #if CONFIG_MACF |
547 | error = mac_proc_check_sched(proc: current_proc(), proc2: target_proc); |
548 | if (error) { |
549 | return error; |
550 | } |
551 | #endif |
552 | switch (action) { |
553 | case PROC_POLICY_ACTION_SET: |
554 | /* PROCESS SET BOOST DONATION */ |
555 | task_importance_mark_donor(task: proc_task(target_proc), TRUE); |
556 | break; |
557 | default: |
558 | error = (EINVAL); |
559 | break; |
560 | } |
561 | break; |
562 | |
563 | default: |
564 | error = (EINVAL); |
565 | break; |
566 | } |
567 | |
568 | return error; |
569 | } |
570 | |
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(thread: 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(thread: current_thread())) { |
611 | return EINVAL; |
612 | } |
613 | if (machine_csv(cve: CPUVN_CI)) { |
614 | machine_tecs(thr: current_thread()); |
615 | } |
616 | } else { |
617 | return EINVAL; |
618 | } |
619 | |
620 | return 0; |
621 | } |
622 | |
623 | /* |
624 | * KPI to determine if a pid is currently backgrounded. |
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) |
631 | { |
632 | proc_t target_proc = PROC_NULL; |
633 | |
634 | if (state == NULL) { |
635 | return EINVAL; |
636 | } |
637 | |
638 | target_proc = proc_find(pid); |
639 | |
640 | if (target_proc == PROC_NULL) { |
641 | return ESRCH; |
642 | } |
643 | |
644 | if (proc_get_effective_task_policy(task: proc_task(target_proc), TASK_POLICY_DARWIN_BG)) { |
645 | *state = 1; |
646 | } else { |
647 | *state = 0; |
648 | } |
649 | |
650 | proc_rele(p: target_proc); |
651 | return 0; |
652 | } |
653 | |
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(); |
665 | uint32_t flagsp = 0; |
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); |
672 | |
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(task: proc_task(p), flagsp: &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: &pid); |
691 | if (kr != KERN_SUCCESS) { |
692 | if (kr == KERN_INVALID_TASK) { |
693 | return ESRCH; |
694 | } else if (kr == KERN_INVALID_VALUE) { |
695 | return ENOATTR; |
696 | } else { |
697 | return EINVAL; |
698 | } |
699 | } |
700 | |
701 | ret = proc_pidbackgrounded(pid, state: is_backgrounded); |
702 | return ret; |
703 | } |
704 | |
705 | int |
706 | proc_apply_resource_actions(void * bsdinfo, __unused int type, int action) |
707 | { |
708 | proc_t p = (proc_t)bsdinfo; |
709 | |
710 | switch (action) { |
711 | case PROC_POLICY_RSRCACT_THROTTLE: |
712 | /* no need to do anything */ |
713 | break; |
714 | |
715 | case PROC_POLICY_RSRCACT_SUSPEND: |
716 | task_suspend(proc_task(p)); |
717 | break; |
718 | |
719 | case PROC_POLICY_RSRCACT_TERMINATE: |
720 | psignal(p, SIGKILL); |
721 | break; |
722 | |
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; |
730 | } |
731 | |
732 | return 0; |
733 | } |
734 | |
735 | int |
736 | proc_restore_resource_actions(void * bsdinfo, __unused int type, int action) |
737 | { |
738 | proc_t p = (proc_t)bsdinfo; |
739 | |
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(proc_task(p)); |
750 | break; |
751 | } |
752 | |
753 | return 0; |
754 | } |
755 | |