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