1/*
2 * Copyright (c) 2013 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 * System Overrides 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/proc.h>
39#include <sys/kauth.h>
40#include <sys/unistd.h>
41#include <sys/priv.h>
42#include <security/audit/audit.h>
43
44#include <mach/mach_types.h>
45#include <mach/vm_param.h>
46#include <kern/task.h>
47#include <kern/lock.h>
48#include <kern/assert.h>
49#include <kern/sched_prim.h>
50
51#include <sys/kern_overrides.h>
52#include <sys/bsdtask_info.h>
53#include <sys/kdebug.h>
54#include <sys/sysproto.h>
55#include <sys/msgbuf.h>
56
57/* Mutex for global system override state */
58static lck_mtx_t	sys_override_lock;
59static lck_grp_t        *sys_override_mtx_grp;
60static lck_attr_t       *sys_override_mtx_attr;
61static lck_grp_attr_t   *sys_override_mtx_grp_attr;
62
63/* Assertion counts for system properties */
64static int64_t		io_throttle_assert_cnt;
65static int64_t		cpu_throttle_assert_cnt;
66
67/* Wait Channel for system override */
68static uint64_t		sys_override_wait;
69
70/* Forward Declarations */
71static void enable_system_override(uint64_t flags);
72static void disable_system_override(uint64_t flags);
73static __attribute__((noinline)) void PROCESS_OVERRIDING_SYSTEM_DEFAULTS(uint64_t timeout);
74
75/***************************** system_override ********************/
76/*
77 * int system_override(uint64_t timeout, uint64_t flags);
78 */
79
80void
81init_system_override()
82{
83	sys_override_mtx_grp_attr = lck_grp_attr_alloc_init();
84	sys_override_mtx_grp = lck_grp_alloc_init("system_override", sys_override_mtx_grp_attr);
85	sys_override_mtx_attr = lck_attr_alloc_init();
86	lck_mtx_init(&sys_override_lock, sys_override_mtx_grp, sys_override_mtx_attr);
87	io_throttle_assert_cnt = cpu_throttle_assert_cnt = 0;
88}
89
90/* system call implementation */
91int
92system_override(__unused struct proc *p, struct system_override_args * uap, __unused int32_t *retval)
93{
94	uint64_t timeout = uap->timeout;
95	uint64_t flags = uap->flags;
96	int error = 0;
97
98	/* Check credentials for caller. Only entitled processes are allowed to make this call. */
99	if ((error = priv_check_cred(kauth_cred_get(), PRIV_SYSTEM_OVERRIDE, 0))) {
100		goto out;
101	}
102
103	/* Check to see if some flags are specified. Zero flags are invalid. */
104	if ((flags == 0) || ((flags & ~SYS_OVERRIDE_FLAGS_MASK) != 0)) {
105		error = EINVAL;
106		goto out;
107	}
108
109	lck_mtx_lock(&sys_override_lock);
110
111	enable_system_override(flags);
112
113	PROCESS_OVERRIDING_SYSTEM_DEFAULTS(timeout);
114
115	disable_system_override(flags);
116
117	lck_mtx_unlock(&sys_override_lock);
118
119out:
120	return error;
121}
122
123/*
124 * Call for enabling global system override.
125 * This should be called only with the sys_override_lock held.
126 */
127static void
128enable_system_override(uint64_t flags)
129{
130
131	if (flags & SYS_OVERRIDE_IO_THROTTLE) {
132		if (io_throttle_assert_cnt == 0) {
133			/* Disable I/O Throttling */
134			printf("Process %s [%d] disabling system-wide I/O Throttling\n", current_proc()->p_comm, current_proc()->p_pid);
135			KERNEL_DEBUG_CONSTANT(FSDBG_CODE(DBG_THROTTLE, IO_THROTTLE_DISABLE) | DBG_FUNC_START, current_proc()->p_pid, 0, 0, 0, 0);
136			sys_override_io_throttle(THROTTLE_IO_DISABLE);
137		}
138		io_throttle_assert_cnt++;
139	}
140
141	if (flags & SYS_OVERRIDE_CPU_THROTTLE) {
142		if (cpu_throttle_assert_cnt == 0) {
143			/* Disable CPU Throttling */
144			printf("Process %s [%d] disabling system-wide CPU Throttling\n", current_proc()->p_comm, current_proc()->p_pid);
145			KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED, MACH_CPU_THROTTLE_DISABLE) | DBG_FUNC_START, current_proc()->p_pid, 0, 0, 0, 0);
146			sys_override_cpu_throttle(CPU_THROTTLE_DISABLE);
147		}
148		cpu_throttle_assert_cnt++;
149	}
150
151}
152
153/*
154 * Call for disabling global system override.
155 * This should be called only with the sys_override_lock held.
156 */
157static void
158disable_system_override(uint64_t flags)
159{
160
161	if (flags & SYS_OVERRIDE_IO_THROTTLE) {
162		assert(io_throttle_assert_cnt > 0);
163		io_throttle_assert_cnt--;
164		if (io_throttle_assert_cnt == 0) {
165			/* Enable I/O Throttling */
166			KERNEL_DEBUG_CONSTANT(FSDBG_CODE(DBG_THROTTLE, IO_THROTTLE_DISABLE) | DBG_FUNC_END, current_proc()->p_pid, 0, 0, 0, 0);
167			sys_override_io_throttle(THROTTLE_IO_ENABLE);
168		}
169	}
170
171	if (flags & SYS_OVERRIDE_CPU_THROTTLE) {
172		assert(cpu_throttle_assert_cnt > 0);
173		cpu_throttle_assert_cnt--;
174			if (cpu_throttle_assert_cnt == 0) {
175			/* Enable CPU Throttling */
176			KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED, MACH_CPU_THROTTLE_DISABLE) | DBG_FUNC_END, current_proc()->p_pid, 0, 0, 0, 0);
177			sys_override_cpu_throttle(CPU_THROTTLE_ENABLE);
178		}
179	}
180}
181
182static __attribute__((noinline)) void
183PROCESS_OVERRIDING_SYSTEM_DEFAULTS(uint64_t timeout)
184{
185	struct timespec ts;
186	ts.tv_sec = timeout / NSEC_PER_SEC;
187	ts.tv_nsec = timeout - ((long)ts.tv_sec * NSEC_PER_SEC);
188	msleep((caddr_t)&sys_override_wait, &sys_override_lock, PRIBIO | PCATCH, "system_override", &ts);
189}
190
191