1 /*
2 * Copyright (c) 2023 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 #if CONFIG_EXCLAVES
30
31 #if DEVELOPMENT || DEBUG
32
33 #include <kern/kalloc.h>
34 #include <kern/locks.h>
35
36 #include "exclaves_debug.h"
37 #include "exclaves_resource.h"
38
39 /* External & generated headers */
40 #include <xrt_hosted_types/types.h>
41 #include <xnuproxy/messages.h>
42
43 #include "exclaves_resource.h"
44 #include "exclaves_xnuproxy.h"
45
46 #if __has_include(<Tightbeam/tightbeam.h>)
47
48 #include <Tightbeam/tightbeam.h>
49 #include <Tightbeam/tightbeam_private.h>
50 #include "kern/exclaves.tightbeam.h"
51
52 #define EXCLAVES_ID_HELLO_EXCLAVE_EP \
53 (exclaves_service_lookup(EXCLAVES_DOMAIN_KERNEL, \
54 "com.apple.service.ExclavesCHelloServer"))
55
56 static int
exclaves_hello_exclave_test(__unused int64_t in,int64_t * out)57 exclaves_hello_exclave_test(__unused int64_t in, int64_t *out)
58 {
59 tb_error_t tb_result;
60 exclaveschelloserver_tests_s client;
61
62 if (exclaves_get_status() != EXCLAVES_STATUS_AVAILABLE) {
63 exclaves_debug_printf(show_test_output,
64 "%s: SKIPPED: Exclaves not available\n", __func__);
65 *out = -1;
66 return 0;
67 }
68
69 exclaves_debug_printf(show_test_output, "%s: STARTING\n", __func__);
70
71 tb_endpoint_t ep = tb_endpoint_create_with_value(TB_TRANSPORT_TYPE_XNU,
72 EXCLAVES_ID_HELLO_EXCLAVE_EP, TB_ENDPOINT_OPTIONS_NONE);
73
74 tb_result = exclaveschelloserver_tests__init(&client, ep);
75 assert3u(tb_result, ==, TB_ERROR_SUCCESS);
76
77 tb_result = exclaveschelloserver_tests_default_hello(&client, ^(uint64_t result) {
78 assert3u(tb_result, ==, TB_ERROR_SUCCESS);
79 assert3u((uint16_t)(result), ==, 0x1338);
80 });
81
82 exclaves_debug_printf(show_test_output, "%s: SUCCESS\n", __func__);
83 *out = 1;
84
85 return KERN_SUCCESS;
86 }
87 SYSCTL_TEST_REGISTER(exclaves_hello_exclave_test, exclaves_hello_exclave_test);
88
89 static int
exclaves_panic_exclave_test(__unused int64_t in,int64_t * out)90 exclaves_panic_exclave_test(__unused int64_t in, int64_t *out)
91 {
92 tb_error_t tb_result;
93 exclaveschelloserver_tests_s client;
94
95 if (exclaves_get_status() != EXCLAVES_STATUS_AVAILABLE) {
96 exclaves_debug_printf(show_test_output,
97 "%s: SKIPPED: Exclaves not available\n", __func__);
98 *out = -1;
99 return 0;
100 }
101
102 exclaves_debug_printf(show_test_output, "%s: STARTING\n", __func__);
103
104 tb_endpoint_t ep = tb_endpoint_create_with_value(TB_TRANSPORT_TYPE_XNU,
105 EXCLAVES_ID_HELLO_EXCLAVE_EP, TB_ENDPOINT_OPTIONS_NONE);
106
107 tb_result = exclaveschelloserver_tests__init(&client, ep);
108 assert3u(tb_result, ==, TB_ERROR_SUCCESS);
109
110 tb_result = exclaveschelloserver_tests_panic_exclave_example(&client);
111
112 /* This should not be reachable. Hence, failed. */
113 exclaves_debug_printf(show_test_output, "%s: FAILED\n", __func__);
114 *out = -1;
115
116 return KERN_SUCCESS;
117 }
118 SYSCTL_TEST_REGISTER(exclaves_panic_exclave_test, exclaves_panic_exclave_test);
119
120 #endif /* __has_include(<Tightbeam/tightbeam.h>) */
121
122 static int
exclaves_sensor_kpi_test(int64_t in,int64_t * out)123 exclaves_sensor_kpi_test(int64_t in, int64_t *out)
124 {
125 #pragma unused(in)
126 #define SENSOR_TEST(x) \
127 if (!(x)) { \
128 exclaves_debug_printf(show_errors, \
129 "%s: FAILURE -- %s:%d\n", __func__, __FILE__, __LINE__); \
130 success = false; \
131 goto out; \
132 }
133
134 bool success = true;
135 exclaves_debug_printf(show_test_output, "%s: STARTING\n", __func__);
136
137 exclaves_sensor_type_t sensors[] = {
138 EXCLAVES_SENSOR_CAM,
139 EXCLAVES_SENSOR_MIC,
140 EXCLAVES_SENSOR_CAM_ALT_FACEID,
141 };
142 unsigned num_sensors = sizeof(sensors) / sizeof(sensors[0]);
143 exclaves_sensor_status_t sensor_status = EXCLAVES_SENSOR_STATUS_DENIED;
144 exclaves_sensor_type_t bad =
145 (exclaves_sensor_type_t) (unsigned) (EXCLAVES_SENSOR_MAX + 1);
146 kern_return_t kr;
147
148 /* invalid sensor */
149 kr = exclaves_sensor_stop(bad, 0, &sensor_status);
150 SENSOR_TEST(kr == KERN_INVALID_ARGUMENT);
151
152 kr = exclaves_sensor_start(bad, 0, &sensor_status);
153 SENSOR_TEST(kr == KERN_INVALID_ARGUMENT);
154
155 kr = exclaves_sensor_status(bad, 0, &sensor_status);
156 SENSOR_TEST(kr == KERN_INVALID_ARGUMENT);
157
158 /* stop before start */
159 for (unsigned i = 0; i < num_sensors; i++) {
160 kr = exclaves_sensor_stop(sensors[i], 0, &sensor_status);
161 SENSOR_TEST(kr == KERN_INVALID_ARGUMENT);
162 }
163
164 /* start status is denied */
165 for (unsigned i = 0; i < num_sensors; i++) {
166 kr = exclaves_sensor_status(sensors[i], 0, &sensor_status);
167 SENSOR_TEST(kr == KERN_SUCCESS);
168 SENSOR_TEST(sensor_status == EXCLAVES_SENSOR_STATUS_ALLOWED); /* Not enforced */
169 }
170
171 /* ALLOWED after at least 1 start */
172 unsigned const n = 5;
173 for (unsigned i = 0; i < num_sensors; i++) {
174 for (unsigned j = 0; j < n; j++) {
175 kr = exclaves_sensor_start(sensors[i], 0, &sensor_status);
176 SENSOR_TEST(kr == KERN_SUCCESS);
177 SENSOR_TEST(sensor_status == EXCLAVES_SENSOR_STATUS_ALLOWED);
178 kr = exclaves_sensor_status(sensors[i], 0, &sensor_status);
179 SENSOR_TEST(kr == KERN_SUCCESS);
180 SENSOR_TEST(sensor_status == EXCLAVES_SENSOR_STATUS_ALLOWED);
181 }
182 }
183
184 /* ALLOWED after n-1 stops */
185 for (unsigned i = 0; i < num_sensors; i++) {
186 for (unsigned j = 0; j < n - 1; j++) {
187 kr = exclaves_sensor_stop(sensors[i], 0, &sensor_status);
188 SENSOR_TEST(kr == KERN_SUCCESS);
189 SENSOR_TEST(sensor_status == EXCLAVES_SENSOR_STATUS_ALLOWED);
190 kr = exclaves_sensor_status(sensors[i], 0, &sensor_status);
191 SENSOR_TEST(kr == KERN_SUCCESS);
192 SENSOR_TEST(sensor_status == EXCLAVES_SENSOR_STATUS_ALLOWED);
193 }
194 }
195
196 /* DENIED after final stop */
197 for (unsigned i = 0; i < num_sensors; i++) {
198 kr = exclaves_sensor_stop(sensors[i], 0, &sensor_status);
199 SENSOR_TEST(kr == KERN_SUCCESS);
200 SENSOR_TEST(sensor_status == EXCLAVES_SENSOR_STATUS_ALLOWED); /* Not enforced */
201 }
202
203 /* exclaves_display_healthcheck_rate does something */
204 kr = exclaves_display_healthcheck_rate(NSEC_PER_SEC / 60);
205 SENSOR_TEST(kr == KERN_SUCCESS);
206
207 #undef SENSOR_TEST
208 out:
209 if (success) {
210 exclaves_debug_printf(show_test_output,
211 "%s: SUCCESS\n", __func__);
212 *out = 1;
213 } else {
214 exclaves_debug_printf(show_errors, "%s: FAILED\n", __func__);
215 *out = 0;
216 }
217 return 0;
218 }
219 SYSCTL_TEST_REGISTER(exclaves_sensor_kpi_test,
220 exclaves_sensor_kpi_test);
221
222 static int
exclaves_check_mem_usage_test(__unused int64_t in,int64_t * out)223 exclaves_check_mem_usage_test(__unused int64_t in, int64_t *out)
224 {
225 if (exclaves_get_status() != EXCLAVES_STATUS_AVAILABLE) {
226 exclaves_debug_printf(show_test_output,
227 "%s: SKIPPED: Exclaves not available\n", __func__);
228 *out = -1;
229 return 0;
230 }
231
232 exclaves_debug_printf(show_test_output, "%s: STARTING\n", __func__);
233
234 kern_return_t r = exclaves_xnuproxy_pmm_usage();
235 if (r == KERN_FAILURE) {
236 exclaves_debug_printf(show_errors,
237 "Exclave Check Memory Usage failed: Kernel Failure\n");
238 return 0;
239 }
240
241 exclaves_debug_printf(show_test_output, "%s: SUCCESS\n", __func__);
242 *out = 1;
243
244 return 0;
245 }
246 SYSCTL_TEST_REGISTER(exclaves_check_mem_usage_test, exclaves_check_mem_usage_test);
247
248
249 #endif /* DEVELOPMENT || DEBUG */
250
251 #endif /* CONFIG_EXCLAVES */
252