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