xref: /xnu-11417.121.6/osfmk/kern/exclaves_shared_memory.c (revision a1e26a70f38d1d7daa7b49b258e2f8538ad81650)
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