1/*
2 * Copyright (c) 2014 Apple 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#include <pexpert/pexpert.h>
30#include <sys/csr.h>
31#include <sys/errno.h>
32#include <sys/sysproto.h>
33#include <sys/systm.h>
34#include <sys/types.h>
35
36/* allow everything by default? */
37/* XXX: set this to 0 later: <rdar://problem/16040413> */
38static int csr_allow_all = 1;
39
40/* allow everything if CSR_ALLOW_APPLE_INTERNAL is set */
41static int csr_allow_internal = 1;
42
43/* Current boot-arg policy:
44 * rootless=0
45 *    csr_allow_all = 1
46 * rootless=1
47 *    csr_allow_all = 0
48 *    csr_allow_internal = 0
49 *
50 * After <rdar://problem/16239861>:
51 * rootless=0
52 *    no effect
53 * rootless=1
54 *    csr_allow_internal = 0
55 *
56 * Enforcement policy:
57 * ===============================
58 *            | csr_allow_internal
59 *            |   0         1
60 * ===============================
61 *   csr_   0 | always   customer
62 *  allow_    |
63 *   all    1 | never    never
64 * ===============================
65 * NB: "customer" means enforce when
66 * CSR_ALLOW_APPLE_INTERNAL not set */
67
68void
69csr_init(void)
70{
71	boot_args *args = (boot_args *)PE_state.bootArgs;
72	if (args->flags & kBootArgsFlagCSRBoot) {
73		/* special booter; allow everything */
74		csr_allow_all = 1;
75	}
76
77	int rootless_boot_arg;
78	if (PE_parse_boot_argn("rootless", &rootless_boot_arg, sizeof(rootless_boot_arg))) {
79		/* XXX: set csr_allow_all to boot arg value for now
80		 * (to be removed by <rdar://problem/16239861>) */
81		csr_allow_all = !rootless_boot_arg;
82		/* if rootless=1, do not allow everything when CSR_ALLOW_APPLE_INTERNAL is set */
83		csr_allow_internal &= !rootless_boot_arg;
84	}
85}
86
87int
88csrctl(__unused proc_t p, struct csrctl_args *uap, __unused int32_t *retval)
89{
90	int error = 0;
91
92	if (uap->useraddr == 0)
93		return EINVAL;
94	if (uap->usersize != sizeof(csr_config_t))
95		return EINVAL;
96
97	switch (uap->op) {
98		case CSR_OP_CHECK:
99		{
100			csr_config_t mask;
101			error = copyin(uap->useraddr, &mask, sizeof(csr_config_t));
102
103			if (error)
104				return error;
105
106			error = csr_check(mask);
107			break;
108		}
109
110		case CSR_OP_GET_ACTIVE_CONFIG:
111		case CSR_OP_GET_PENDING_CONFIG: /* fall through */
112		{
113			csr_config_t config = 0;
114			if (uap->op == CSR_OP_GET_ACTIVE_CONFIG)
115				error = csr_get_active_config(&config);
116			else
117				error = csr_get_pending_config(&config);
118
119			if (error)
120				return error;
121
122			error = copyout(&config, uap->useraddr, sizeof(csr_config_t));
123			break;
124		}
125
126		default:
127			error = EINVAL;
128			break;
129	}
130
131	return error;
132}
133
134int
135csr_get_active_config(csr_config_t *config)
136{
137	boot_args *args = (boot_args *)PE_state.bootArgs;
138	if (args->flags & kBootArgsFlagCSRActiveConfig) {
139		*config = args->csrActiveConfig & CSR_VALID_FLAGS;
140	} else {
141		/* XXX: change to 0 when <rdar://problem/16239698> is in the build */
142		*config = CSR_ALLOW_APPLE_INTERNAL;
143	}
144
145	return 0;
146}
147
148int
149csr_get_pending_config(csr_config_t *config)
150{
151	boot_args *args = (boot_args *)PE_state.bootArgs;
152	if (args->flags & kBootArgsFlagCSRPendingConfig) {
153		*config = args->csrPendingConfig & CSR_VALID_FLAGS;
154		return 0;
155	} else {
156		return ENOENT;
157	}
158}
159
160int
161csr_check(csr_config_t mask)
162{
163	if (csr_allow_all) {
164		return 0;
165	}
166
167	csr_config_t config;
168	int error = csr_get_active_config(&config);
169	if (error) {
170		return error;
171	}
172
173	if (csr_allow_internal && (config & CSR_ALLOW_APPLE_INTERNAL)) {
174		return 0;
175	}
176
177	if (mask == 0) {
178		/* pass 0 to check if Rootless enforcement is active */
179		return -1;
180	}
181
182	error = (config & mask) ? 0 : EPERM;
183	return error;
184}
185
186void
187csr_set_allow_all(int value)
188{
189	csr_allow_all = !!value; // force value to 0 or 1
190}
191