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
);
64 int sfi_ctl(struct proc
*p __unused
, struct sfi_ctl_args
*uap
, int32_t *retval __unused
)
66 uint32_t operation
= uap
->operation
;
68 kern_return_t kret
= KERN_SUCCESS
;
69 uint64_t out_time
= 0;
72 case SFI_CTL_OPERATION_SFI_SET_WINDOW
:
73 if (uap
->out_time
!= USER_ADDR_NULL
) {
76 if (uap
->sfi_class
!= SFI_CLASS_UNSPECIFIED
) {
80 error
= priv_check_cred(kauth_cred_get(), PRIV_SELECTIVE_FORCED_IDLE
, 0);
82 dprintf("%s failed privilege check for sfi_ctl: %d\n", p
->p_comm
, error
);
85 dprintf("%s succeeded privilege check for sfi_ctl\n", p
->p_comm
);
89 /* actually a cancel */
90 kret
= sfi_window_cancel();
92 kret
= sfi_set_window(uap
->time
);
100 case SFI_CTL_OPERATION_SFI_GET_WINDOW
:
101 if (uap
->time
!= 0) {
104 if (uap
->sfi_class
!= SFI_CLASS_UNSPECIFIED
) {
108 kret
= sfi_get_window(&out_time
);
109 if (kret
== KERN_SUCCESS
) {
110 error
= copyout(&out_time
, uap
->out_time
, sizeof(out_time
));
116 case SFI_CTL_OPERATION_SET_CLASS_OFFTIME
:
117 if (uap
->out_time
!= USER_ADDR_NULL
) {
121 error
= priv_check_cred(kauth_cred_get(), PRIV_SELECTIVE_FORCED_IDLE
, 0);
123 dprintf("%s failed privilege check for sfi_ctl: %d\n", p
->p_comm
, error
);
126 dprintf("%s succeeded privilege check for sfi_ctl\n", p
->p_comm
);
129 if (uap
->time
== 0) {
130 /* actually a cancel */
131 kret
= sfi_class_offtime_cancel(uap
->sfi_class
);
133 kret
= sfi_set_class_offtime(uap
->sfi_class
, uap
->time
);
141 case SFI_CTL_OPERATION_GET_CLASS_OFFTIME
:
142 if (uap
->time
!= 0) {
146 kret
= sfi_get_class_offtime(uap
->sfi_class
, &out_time
);
147 if (kret
== KERN_SUCCESS
) {
148 error
= copyout(&out_time
, uap
->out_time
, sizeof(out_time
));
162 static int proc_apply_sfi_managed(proc_t p
, void * arg
)
164 uint32_t flags
= *(uint32_t *)arg
;
165 pid_t pid
= p
->p_pid
;
166 boolean_t managed_enabled
= (flags
== SFI_PROCESS_SET_MANAGED
)? TRUE
: FALSE
;
168 if (pid
== 0) { /* ignore setting on kernproc */
169 return PROC_RETURNED
;
172 if (managed_enabled
) {
173 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SFI
, SFI_PID_SET_MANAGED
) | DBG_FUNC_NONE
, pid
, 0, 0, 0, 0);
175 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SFI
, SFI_PID_CLEAR_MANAGED
) | DBG_FUNC_NONE
, pid
, 0, 0, 0, 0);
178 proc_set_task_policy(p
->task
,
179 TASK_POLICY_ATTRIBUTE
, TASK_POLICY_SFI_MANAGED
,
180 managed_enabled
? TASK_POLICY_ENABLE
: TASK_POLICY_DISABLE
);
182 return PROC_RETURNED
;
185 int sfi_pidctl(struct proc
*p __unused
, struct sfi_pidctl_args
*uap
, int32_t *retval __unused
)
187 uint32_t operation
= uap
->operation
;
188 pid_t pid
= uap
->pid
;
190 uint32_t out_flags
= 0;
191 boolean_t managed_enabled
;
195 case SFI_PIDCTL_OPERATION_PID_SET_FLAGS
:
196 if (uap
->out_sfi_flags
!= USER_ADDR_NULL
197 || !(uap
->sfi_flags
& SFI_PROCESS_SET_MANAGED_MASK
)
198 || uap
->sfi_flags
== SFI_PROCESS_SET_MANAGED_MASK
) {
202 error
= priv_check_cred(kauth_cred_get(), PRIV_SELECTIVE_FORCED_IDLE
, 0);
204 dprintf("%s failed privilege check for sfi_pidctl: %d\n", p
->p_comm
, error
);
207 dprintf("%s succeeded privilege check for sfi_pidctl\n", p
->p_comm
);
211 /* only allow SFI_PROCESS_SET_UNMANAGED for pid 0 */
212 if (uap
->sfi_flags
!= SFI_PROCESS_SET_UNMANAGED
) {
216 proc_iterate(PROC_ALLPROCLIST
, proc_apply_sfi_managed
, (void *)&uap
->sfi_flags
, NULL
, NULL
);
220 targetp
= proc_find(pid
);
226 proc_apply_sfi_managed(targetp
, (void *)&uap
->sfi_flags
);
231 case SFI_PIDCTL_OPERATION_PID_GET_FLAGS
:
232 if (uap
->sfi_flags
!= 0) {
239 targetp
= proc_find(pid
);
245 managed_enabled
= proc_get_task_policy(targetp
->task
, TASK_POLICY_ATTRIBUTE
, TASK_POLICY_SFI_MANAGED
);
249 out_flags
= managed_enabled
? SFI_PROCESS_SET_MANAGED
: SFI_PROCESS_SET_UNMANAGED
;
251 error
= copyout(&out_flags
, uap
->out_sfi_flags
, sizeof(out_flags
));