2 * Copyright (c) 2013 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 #include <kern/assert.h>
31 #include <kern/locks.h>
32 #include <kern/task.h>
33 #include <kern/thread.h>
35 #include <libkern/libkern.h>
36 #include <mach/mach_time.h>
37 #include <pexpert/pexpert.h>
39 #include <sys/proc_info.h>
40 #include <sys/sysproto.h>
42 #include <sys/kdebug.h>
44 #include <kern/policy_internal.h>
47 * This file provides the syscall-based configuration facility
48 * for Selective Forced Idle (SFI). Input arguments have basic checking
49 * applied here, although more specific semantic checking is done in
50 * osfmk/kern/sfi.c. All copyin()/copyout() operations are performed
51 * in this source file.
57 #define dprintf(...) printf(__VA_ARGS__)
59 #define dprintf(...) do { } while(0)
62 static int proc_apply_sfi_managed(proc_t p
, void * arg
);
65 sfi_ctl(struct proc
*p __unused
, struct sfi_ctl_args
*uap
, int32_t *retval __unused
)
67 uint32_t operation
= uap
->operation
;
69 kern_return_t kret
= KERN_SUCCESS
;
70 uint64_t out_time
= 0;
73 case SFI_CTL_OPERATION_SFI_SET_WINDOW
:
74 if (uap
->out_time
!= USER_ADDR_NULL
) {
77 if (uap
->sfi_class
!= SFI_CLASS_UNSPECIFIED
) {
81 error
= priv_check_cred(kauth_cred_get(), PRIV_SELECTIVE_FORCED_IDLE
, 0);
83 dprintf("%s failed privilege check for sfi_ctl: %d\n", p
->p_comm
, error
);
86 dprintf("%s succeeded privilege check for sfi_ctl\n", p
->p_comm
);
90 /* actually a cancel */
91 kret
= sfi_window_cancel();
93 kret
= sfi_set_window(uap
->time
);
101 case SFI_CTL_OPERATION_SFI_GET_WINDOW
:
102 if (uap
->time
!= 0) {
105 if (uap
->sfi_class
!= SFI_CLASS_UNSPECIFIED
) {
109 kret
= sfi_get_window(&out_time
);
110 if (kret
== KERN_SUCCESS
) {
111 error
= copyout(&out_time
, uap
->out_time
, sizeof(out_time
));
117 case SFI_CTL_OPERATION_SET_CLASS_OFFTIME
:
118 if (uap
->out_time
!= USER_ADDR_NULL
) {
122 error
= priv_check_cred(kauth_cred_get(), PRIV_SELECTIVE_FORCED_IDLE
, 0);
124 dprintf("%s failed privilege check for sfi_ctl: %d\n", p
->p_comm
, error
);
127 dprintf("%s succeeded privilege check for sfi_ctl\n", p
->p_comm
);
130 if (uap
->time
== 0) {
131 /* actually a cancel */
132 kret
= sfi_class_offtime_cancel(uap
->sfi_class
);
134 kret
= sfi_set_class_offtime(uap
->sfi_class
, uap
->time
);
142 case SFI_CTL_OPERATION_GET_CLASS_OFFTIME
:
143 if (uap
->time
!= 0) {
147 kret
= sfi_get_class_offtime(uap
->sfi_class
, &out_time
);
148 if (kret
== KERN_SUCCESS
) {
149 error
= copyout(&out_time
, uap
->out_time
, sizeof(out_time
));
164 proc_apply_sfi_managed(proc_t p
, void * arg
)
166 uint32_t flags
= *(uint32_t *)arg
;
167 pid_t pid
= p
->p_pid
;
168 boolean_t managed_enabled
= (flags
== SFI_PROCESS_SET_MANAGED
)? TRUE
: FALSE
;
170 if (pid
== 0) { /* ignore setting on kernproc */
171 return PROC_RETURNED
;
174 if (managed_enabled
) {
175 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SFI
, SFI_PID_SET_MANAGED
) | DBG_FUNC_NONE
, pid
, 0, 0, 0, 0);
177 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SFI
, SFI_PID_CLEAR_MANAGED
) | DBG_FUNC_NONE
, pid
, 0, 0, 0, 0);
180 proc_set_task_policy(p
->task
,
181 TASK_POLICY_ATTRIBUTE
, TASK_POLICY_SFI_MANAGED
,
182 managed_enabled
? TASK_POLICY_ENABLE
: TASK_POLICY_DISABLE
);
184 return PROC_RETURNED
;
188 sfi_pidctl(struct proc
*p __unused
, struct sfi_pidctl_args
*uap
, int32_t *retval __unused
)
190 uint32_t operation
= uap
->operation
;
191 pid_t pid
= uap
->pid
;
193 uint32_t out_flags
= 0;
194 boolean_t managed_enabled
;
198 case SFI_PIDCTL_OPERATION_PID_SET_FLAGS
:
199 if (uap
->out_sfi_flags
!= USER_ADDR_NULL
200 || !(uap
->sfi_flags
& SFI_PROCESS_SET_MANAGED_MASK
)
201 || uap
->sfi_flags
== SFI_PROCESS_SET_MANAGED_MASK
) {
205 error
= priv_check_cred(kauth_cred_get(), PRIV_SELECTIVE_FORCED_IDLE
, 0);
207 dprintf("%s failed privilege check for sfi_pidctl: %d\n", p
->p_comm
, error
);
210 dprintf("%s succeeded privilege check for sfi_pidctl\n", p
->p_comm
);
214 /* only allow SFI_PROCESS_SET_UNMANAGED for pid 0 */
215 if (uap
->sfi_flags
!= SFI_PROCESS_SET_UNMANAGED
) {
219 proc_iterate(PROC_ALLPROCLIST
, proc_apply_sfi_managed
, (void *)&uap
->sfi_flags
, NULL
, NULL
);
223 targetp
= proc_find(pid
);
229 proc_apply_sfi_managed(targetp
, (void *)&uap
->sfi_flags
);
234 case SFI_PIDCTL_OPERATION_PID_GET_FLAGS
:
235 if (uap
->sfi_flags
!= 0) {
242 targetp
= proc_find(pid
);
248 managed_enabled
= proc_get_task_policy(targetp
->task
, TASK_POLICY_ATTRIBUTE
, TASK_POLICY_SFI_MANAGED
);
252 out_flags
= managed_enabled
? SFI_PROCESS_SET_MANAGED
: SFI_PROCESS_SET_UNMANAGED
;
254 error
= copyout(&out_flags
, uap
->out_sfi_flags
, sizeof(out_flags
));