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 #include <stdint.h>
32 #include <mach/kern_return.h>
33 #include <kern/assert.h>
34 #include <kern/misc_protos.h>
35
36 #include "exclaves_debug.h"
37 #include "exclaves_shared_memory.h"
38 #include "kern/exclaves.tightbeam.h"
39
40 kern_return_t
exclaves_shared_memory_init(const uint64_t endpoint,sharedmemorybase_segxnuaccess_s * sm_client)41 exclaves_shared_memory_init(const uint64_t endpoint,
42 sharedmemorybase_segxnuaccess_s *sm_client)
43 {
44 assert3p(sm_client, !=, NULL);
45
46 tb_endpoint_t ep = tb_endpoint_create_with_value(
47 TB_TRANSPORT_TYPE_XNU, endpoint, TB_ENDPOINT_OPTIONS_NONE);
48 tb_error_t ret = sharedmemorybase_segxnuaccess__init(sm_client, ep);
49
50 return ret == TB_ERROR_SUCCESS ? KERN_SUCCESS : KERN_FAILURE;
51 }
52
53 static kern_return_t
exclaves_shared_memory_access_check(const sharedmemorybase_segxnuaccess_s * sm_client,const sharedmemorybase_perms_s perm,const uint64_t endpage)54 exclaves_shared_memory_access_check(
55 const sharedmemorybase_segxnuaccess_s *sm_client,
56 const sharedmemorybase_perms_s perm, const uint64_t endpage)
57 {
58 assert3p(sm_client, !=, NULL);
59
60 __block kern_return_t kr = KERN_SUCCESS;
61 tb_error_t ret = TB_ERROR_SUCCESS;
62
63 ret = sharedmemorybase_segxnuaccess_xnuaccessstatus(sm_client,
64 ^(sharedmemorybase_accessstatus_s result) {
65 /*
66 * Check permissions.
67 * For the moment just check for writable
68 * access (if relevant).
69 */
70 if (perm != result.permissions) {
71 kr = KERN_PROTECTION_FAILURE;
72 return;
73 }
74
75 if (!result.xnu) {
76 kr = KERN_FAILURE;
77 return;
78 }
79
80 if (endpage > result.segmentstatus.npages) {
81 kr = KERN_FAILURE;
82 return;
83 }
84 });
85
86 if (ret != TB_ERROR_SUCCESS) {
87 return KERN_FAILURE;
88 }
89
90 return kr;
91 }
92
93 kern_return_t
exclaves_shared_memory_setup(const sharedmemorybase_segxnuaccess_s * sm_client,const sharedmemorybase_perms_s perm,const uint64_t startpage,const uint64_t endpage,sharedmemorybase_mapping_s * mapping)94 exclaves_shared_memory_setup(const sharedmemorybase_segxnuaccess_s *sm_client,
95 const sharedmemorybase_perms_s perm, const uint64_t startpage,
96 const uint64_t endpage, sharedmemorybase_mapping_s *mapping)
97 {
98 assert3p(sm_client, !=, NULL);
99 assert3p(mapping, !=, NULL);
100 assert3u(startpage, <, endpage);
101 assert(perm == SHAREDMEMORYBASE_PERMS_READWRITE ||
102 perm == SHAREDMEMORYBASE_PERMS_READONLY);
103
104 tb_error_t ret = TB_ERROR_SUCCESS;
105
106 /* Do a quick sanity check that this access is allowed. */
107 kern_return_t kret = exclaves_shared_memory_access_check(sm_client,
108 perm, endpage);
109 if (kret != KERN_SUCCESS) {
110 return kret;
111 }
112
113 sharedmemorybase_pagerange__opt_s opt_range = {};
114
115 sharedmemorybase_pagerange_s range = {
116 .startpage = startpage,
117 .endpage = endpage,
118 };
119 sharedmemorybase_pagerange__opt_init(&opt_range, &range);
120
121 *mapping = 0;
122
123 /* BEGIN IGNORE CODESTYLE */
124 ret = sharedmemorybase_segxnuaccess_createxnumapping(sm_client, perm,
125 &opt_range,
126 ^(sharedmemorybase_segxnuaccess_createxnumapping__result_s result) {
127 sharedmemorybase_accesserror_s *error = NULL;
128 error = sharedmemorybase_segxnuaccess_createxnumapping__result_get_failure(&result);
129 if (error != NULL) {
130 exclaves_debug_printf(show_errors,
131 "%s: failed to create mapping: %u", __func__, *error);
132 return;
133 }
134
135 sharedmemorybase_mappingresult_s *sm_result = NULL;
136 sm_result = sharedmemorybase_segxnuaccess_createxnumapping__result_get_success(&result);
137 assert3p(sm_result, !=, NULL);
138
139 *mapping = sm_result->mappinginfo.mapping;
140 assert3u(*mapping, !=, 0);
141 });
142 /* END IGNORE CODESTYLE */
143
144 if (ret != TB_ERROR_SUCCESS || *mapping == 0) {
145 return KERN_FAILURE;
146 }
147
148 return KERN_SUCCESS;
149 }
150
151 /*
152 * Currently unused as the setup process can provide an initial mapping.
153 */
154 kern_return_t
exclaves_shared_memory_teardown(const sharedmemorybase_segxnuaccess_s * sm_client,const sharedmemorybase_mapping_s * mapping)155 exclaves_shared_memory_teardown(const sharedmemorybase_segxnuaccess_s *sm_client,
156 const sharedmemorybase_mapping_s *mapping)
157 {
158 assert3p(sm_client, !=, NULL);
159 assert3p(mapping, !=, NULL);
160
161 tb_error_t ret = TB_ERROR_SUCCESS;
162 __block bool success = false;
163
164 /* BEGIN IGNORE CODESTYLE */
165 ret = sharedmemorybase_segxnuaccess_mappingdestroy(sm_client, *mapping,
166 ^(sharedmemorybase_segaccessbase_mappingdestroy__result_s result) {
167 sharedmemorybase_accesserror_s *error;
168 error = sharedmemorybase_segaccessbase_mappingdestroy__result_get_failure(&result);
169 if (error != NULL) {
170 exclaves_debug_printf(show_errors,
171 "%s: failed to destroy mapping: %u\n", __func__, *error);
172 return;
173 }
174
175 assert(sharedmemorybase_segaccessbase_mappingdestroy__result_get_success(&result));
176 success = true;
177 });
178 /* END IGNORE CODESTYLE */
179
180 if (ret != TB_ERROR_SUCCESS || !success) {
181 return KERN_FAILURE;
182 }
183
184 return KERN_SUCCESS;
185 }
186
187 /*
188 * Currently unused as the teardown process unmaps.
189 */
190 kern_return_t
exclaves_shared_memory_map(const sharedmemorybase_segxnuaccess_s * sm_client,const sharedmemorybase_mapping_s * mapping,const uint64_t startpage,const uint64_t endpage)191 exclaves_shared_memory_map(const sharedmemorybase_segxnuaccess_s *sm_client,
192 const sharedmemorybase_mapping_s *mapping, const uint64_t startpage,
193 const uint64_t endpage)
194 {
195 assert3p(sm_client, !=, NULL);
196 assert3p(mapping, !=, NULL);
197 assert3u(startpage, <, endpage);
198
199 tb_error_t ret = TB_ERROR_SUCCESS;
200 __block bool success = false;
201
202 const sharedmemorybase_pagerange_s range = {
203 .startpage = startpage,
204 .endpage = endpage,
205 };
206
207 /* BEGIN IGNORE CODESTYLE */
208 ret = sharedmemorybase_segxnuaccess_mappingmap(sm_client, *mapping,
209 &range, ^(sharedmemorybase_segaccessbase_mappingmap__result_s result) {
210 sharedmemorybase_accesserror_s *error;
211 error = sharedmemorybase_segaccessbase_mappingmap__result_get_failure(&result);
212 if (error != NULL) {
213 exclaves_debug_printf(show_errors,
214 "%s: failed to map: %u\n", __func__, *error);
215 return;
216 }
217
218 assert(sharedmemorybase_segaccessbase_mappingmap__result_get_success(&result));
219 success = true;
220 });
221 /* END IGNORE CODESTYLE */
222
223 if (ret != TB_ERROR_SUCCESS || !success) {
224 return KERN_FAILURE;
225 }
226
227 return KERN_SUCCESS;
228 }
229
230
231 kern_return_t
exclaves_shared_memory_unmap(const sharedmemorybase_segxnuaccess_s * sm_client,const sharedmemorybase_mapping_s * mapping,const uint64_t startpage,const uint64_t endpage)232 exclaves_shared_memory_unmap(const sharedmemorybase_segxnuaccess_s *sm_client,
233 const sharedmemorybase_mapping_s *mapping, const uint64_t startpage,
234 const uint64_t endpage)
235 {
236 assert3p(sm_client, !=, NULL);
237 assert3p(mapping, !=, NULL);
238 assert3u(startpage, <, endpage);
239
240 tb_error_t ret = TB_ERROR_SUCCESS;
241 __block bool success = false;
242
243 const sharedmemorybase_pagerange_s range = {
244 .startpage = startpage,
245 .endpage = endpage,
246 };
247
248 /* BEGIN IGNORE CODESTYLE */
249 ret = sharedmemorybase_segxnuaccess_mappingunmap(sm_client, *mapping,
250 &range, ^(sharedmemorybase_segaccessbase_mappingunmap__result_s result) {
251 sharedmemorybase_accesserror_s *error;
252 error = sharedmemorybase_segaccessbase_mappingunmap__result_get_failure(&result);
253 if (error != NULL) {
254 exclaves_debug_printf(show_errors, "%s: failed to unmap: %u\n",
255 __func__, *error);
256 return;
257 }
258
259 assert(sharedmemorybase_segaccessbase_mappingunmap__result_get_success(&result));
260 success = true;
261 });
262 /* END IGNORE CODESTYLE */
263
264 if (ret != TB_ERROR_SUCCESS || !success) {
265 return KERN_FAILURE;
266 }
267
268 return KERN_SUCCESS;
269 }
270
271 kern_return_t
272 exclaves_shared_memory_iterate(const sharedmemorybase_segxnuaccess_s *sm_client,
273 const sharedmemorybase_mapping_s *mapping, uint64_t startpage, uint64_t endpage,
274 void (^cb)(uint64_t))
275 {
276 assert3p(sm_client, !=, NULL);
277 assert3p(mapping, !=, NULL);
278 assert3u(startpage, <, endpage);
279
280 tb_error_t ret = TB_ERROR_SUCCESS;
281 __block bool success = false;
282
283 sharedmemorybase_pagerange_s full_range = {
284 .startpage = startpage,
285 .endpage = endpage,
286 };
287
288 /* BEGIN IGNORE CODESTYLE */
289 ret = sharedmemorybase_segxnuaccess_mappinggetphysicaladdresses(sm_client,
290 *mapping, &full_range,
291 ^(sharedmemorybase_segaccessbase_mappinggetphysicaladdresses__result_s result) {
292 sharedmemorybase_accesserror_s *error = NULL;
293 error = sharedmemorybase_segaccessbase_mappinggetphysicaladdresses__result_get_failure(&result);
294 if (error != NULL) {
295 exclaves_debug_printf(show_errors,
296 "%s: failed to get physical address: %u",
297 __func__, *error);
298 return;
299 }
300
301 physicaladdress_v_s *phys_addr = NULL;
302 phys_addr = sharedmemorybase_segaccessbase_mappinggetphysicaladdresses__result_get_success(&result);
303 assert3p(phys_addr, !=, NULL);
304
305 physicaladdress__v_visit(phys_addr,
306 ^(__unused size_t i, const sharedmemorybase_physicaladdress_s item) {
307 cb(item);
308 });
309
310 success = true;
311 });
312 /* END IGNORE CODESTYLE */
313
314 if (ret != TB_ERROR_SUCCESS || !success) {
315 return KERN_FAILURE;
316 }
317
318 return KERN_SUCCESS;
319 }
320
321 #endif /* CONFIG_EXCLAVES */
322