xref: /xnu-11215.1.10/osfmk/kern/exclaves_storage.c (revision 8d741a5de7ff4191bf97d57b9f54c2f6d4a15585)
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 __has_include(<Tightbeam/tightbeam.h>)
32 
33 #include <stdint.h>
34 #include <vm/pmap.h>
35 
36 #include <Tightbeam/tightbeam.h>
37 #include <Tightbeam/tightbeam_private.h>
38 
39 #include <mach/exclaves.h>
40 #include <sys/errno.h>
41 #include <vfs/vfs_exclave_fs.h>
42 #include <kern/kalloc.h>
43 
44 #include "kern/exclaves.tightbeam.h"
45 #include "exclaves_debug.h"
46 #include "exclaves_storage.h"
47 #include "exclaves_boot.h"
48 
49 static const char *STORAGE_EXCLAVE_BUF_ID = "com.apple.named_buffer.6";
50 #define STORAGE_EXCLAVE_BUF_SIZE (4 * 1024 * 1024)
51 
52 static int
verify_string_length(const char * str,size_t size)53 verify_string_length(const char *str, size_t size)
54 {
55 	return (strnlen(str, size) < size) ? 0 : ERANGE;
56 }
57 
58 static int
verify_storage_buf_offset(uint64_t buf,uint64_t length)59 verify_storage_buf_offset(uint64_t buf, uint64_t length)
60 {
61 	uint64_t off;
62 	if (__builtin_add_overflow(buf, length, &off)) {
63 		return ERANGE;
64 	}
65 
66 	if (off > STORAGE_EXCLAVE_BUF_SIZE) {
67 		return ERANGE;
68 	}
69 
70 	return 0;
71 }
72 
73 
74 /* -------------------------------------------------------------------------- */
75 #pragma mark Upcalls
76 
77 tb_error_t
78 exclaves_storage_upcall_root(const uint8_t exclaveid[_Nonnull 32],
79     tb_error_t (^completion)(xnuupcalls_xnuupcalls_root__result_s))
80 {
81 	exclaves_debug_printf(show_storage_upcalls,
82 	    "[storage_upcalls_server] root %s\n", exclaveid);
83 
84 	int error;
85 	uint64_t rootid;
86 	xnuupcalls_xnuupcalls_root__result_s result = {};
87 
88 	if ((error = verify_string_length((const char *)&exclaveid[0], 32))) {
89 		xnuupcalls_xnuupcalls_root__result_init_failure(&result, error);
90 		return completion(result);
91 	}
92 	error = vfs_exclave_fs_root((const char *)&exclaveid[0], &rootid);
93 	if (error) {
94 		exclaves_debug_printf(show_errors,
95 		    "[storage_upcalls_server] vfs_exclave_fs_root failed with %d\n",
96 		    error);
97 		xnuupcalls_xnuupcalls_root__result_init_failure(&result, error);
98 	} else {
99 		exclaves_debug_printf(show_storage_upcalls,
100 		    "[storage_upcalls_server] vfs_exclave_fs_root return "
101 		    "rootId %lld\n", rootid);
102 		xnuupcalls_xnuupcalls_root__result_init_success(&result, rootid);
103 	}
104 
105 	return completion(result);
106 }
107 
108 tb_error_t
109 exclaves_storage_upcall_open(const enum xnuupcalls_fstag_s fstag,
110     const uint64_t rootid, const uint8_t name[_Nonnull 256],
111     tb_error_t (^completion)(xnuupcalls_xnuupcalls_open__result_s))
112 {
113 	exclaves_debug_printf(show_storage_upcalls, "[storage_upcalls_server] "
114 	    "open %d %lld %s\n", fstag, rootid, name);
115 	int error;
116 	uint64_t fileid;
117 	xnuupcalls_xnuupcalls_open__result_s result = {};
118 
119 	if ((error = verify_string_length((const char *)&name[0], 256))) {
120 		xnuupcalls_xnuupcalls_open__result_init_failure(&result, error);
121 		return completion(result);
122 	}
123 	error = vfs_exclave_fs_open((uint32_t)fstag, rootid,
124 	    (const char *)&name[0], &fileid);
125 	if (error) {
126 		exclaves_debug_printf(show_errors,
127 		    "[storage_upcalls_server] vfs_exclave_fs_open failed with %d\n",
128 		    error);
129 		xnuupcalls_xnuupcalls_open__result_init_failure(&result, error);
130 	} else {
131 		exclaves_debug_printf(show_storage_upcalls,
132 		    "[storage_upcalls_server] vfs_exclave_fs_open return "
133 		    "fileId %lld\n", fileid);
134 		xnuupcalls_xnuupcalls_open__result_init_success(&result, fileid);
135 	}
136 
137 	return completion(result);
138 }
139 
140 tb_error_t
141 exclaves_storage_upcall_close(const enum xnuupcalls_fstag_s fstag,
142     const uint64_t fileid, tb_error_t (^completion)(xnuupcalls_xnuupcalls_close__result_s))
143 {
144 	exclaves_debug_printf(show_storage_upcalls, "[storage_upcalls_server] "
145 	    "close %d %lld\n", fstag, fileid);
146 	int error;
147 	xnuupcalls_xnuupcalls_close__result_s result = {};
148 
149 	error = vfs_exclave_fs_close((uint32_t)fstag, fileid);
150 	if (error) {
151 		exclaves_debug_printf(show_errors,
152 		    "[storage_upcalls_server] vfs_exclave_fs_close failed with "
153 		    "%d\n", error);
154 		xnuupcalls_xnuupcalls_close__result_init_failure(&result, error);
155 	} else {
156 		exclaves_debug_printf(show_storage_upcalls,
157 		    "[storage_upcalls_server] vfs_exclave_fs_close succeeded\n");
158 		xnuupcalls_xnuupcalls_close__result_init_success(&result);
159 	}
160 
161 	return completion(result);
162 }
163 
164 tb_error_t
165 exclaves_storage_upcall_create(const enum xnuupcalls_fstag_s fstag,
166     const uint64_t rootid, const uint8_t name[_Nonnull 256],
167     tb_error_t (^completion)(xnuupcalls_xnuupcalls_create__result_s))
168 {
169 	exclaves_debug_printf(show_storage_upcalls, "[storage_upcalls_server]"
170 	    " create %d %lld %s\n", fstag, rootid, name);
171 	int error;
172 	uint64_t fileid;
173 	xnuupcalls_xnuupcalls_create__result_s result = {};
174 
175 	if ((error = verify_string_length((const char *)&name[0], 256))) {
176 		xnuupcalls_xnuupcalls_create__result_init_failure(&result, error);
177 		return completion(result);
178 	}
179 	error = vfs_exclave_fs_create((uint32_t)fstag, rootid,
180 	    (const char *)&name[0], &fileid);
181 	if (error) {
182 		exclaves_debug_printf(show_errors,
183 		    "[storage_upcalls_server] vfs_exclave_fs_create failed with"
184 		    " %d\n", error);
185 		xnuupcalls_xnuupcalls_create__result_init_failure(&result, error);
186 	} else {
187 		exclaves_debug_printf(show_storage_upcalls,
188 		    "[storage_upcalls_server] vfs_exclave_fs_create return "
189 		    "fileId %lld\n", fileid);
190 		xnuupcalls_xnuupcalls_create__result_init_success(&result, fileid);
191 	}
192 
193 	return completion(result);
194 }
195 
196 // Borrowed from bsd_init.c
197 extern bool bsd_rooted_ramdisk(void);
198 
199 static bool
is_restore(void)200 is_restore(void)
201 {
202 	bool is_restore = false;
203 	(void) PE_parse_boot_argn("-restore", &is_restore, sizeof(is_restore));
204 	return is_restore;
205 }
206 
207 static bool
dt_string_is_equal(DTEntry * entry,const char * name,const char * str)208 dt_string_is_equal(DTEntry *entry, const char *name, const char *str)
209 {
210 	const void       *value;
211 	unsigned         size;
212 	size_t           str_size;
213 
214 	str_size = strlen(str) + 1;
215 	return entry != NULL &&
216 	       SecureDTGetProperty(*entry, name, &value, &size) == kSuccess &&
217 	       value != NULL &&
218 	       size == str_size &&
219 	       strncmp(str, value, str_size) == 0;
220 }
221 
222 static bool
is_recovery_environment(void)223 is_recovery_environment(void)
224 {
225 	DTEntry chosen;
226 
227 #if defined(XNU_TARGET_OS_OSX)
228 	const char * environment = "recoveryos";
229 #else
230 	const char * environment = "recovery";
231 #endif
232 
233 	return SecureDTLookupEntry(0, "/chosen", &chosen) == kSuccess &&
234 	       dt_string_is_equal(&chosen, "osenvironment", environment);
235 }
236 
237 static exclaves_resource_t *storage_resource = NULL;
238 static int use_shared_mem_vers = 0;
239 
240 static kern_return_t
exclaves_storage_init(void)241 exclaves_storage_init(void)
242 {
243 	const char *v2_seg_name = "com.apple.storage.backend";
244 
245 	kern_return_t kr = exclaves_resource_shared_memory_map(
246 		EXCLAVES_DOMAIN_KERNEL, v2_seg_name,
247 		STORAGE_EXCLAVE_BUF_SIZE,
248 		EXCLAVES_BUFFER_PERM_WRITE,
249 		&storage_resource);
250 
251 	if (kr == KERN_SUCCESS) {
252 		use_shared_mem_vers = 2;
253 		exclaves_debug_printf(show_storage_upcalls,
254 		    "[storage_upcalls] Using SharedMemory V2 segment for IO");
255 		return kr;
256 	}
257 
258 	if (kr != KERN_NOT_FOUND) {
259 		exclaves_debug_printf(show_errors,
260 		    "[storage_upcalls] Cannot map shared memory segment '%s': failed with %d\n",
261 		    v2_seg_name, kr);
262 	}
263 
264 	kr = exclaves_named_buffer_map(
265 		EXCLAVES_DOMAIN_KERNEL, STORAGE_EXCLAVE_BUF_ID,
266 		STORAGE_EXCLAVE_BUF_SIZE,
267 		EXCLAVES_BUFFER_PERM_READ | EXCLAVES_BUFFER_PERM_WRITE,
268 		&storage_resource);
269 	if (kr != KERN_SUCCESS) {
270 		exclaves_debug_printf(show_errors,
271 		    "[storage_upcalls] exclaves_named_buffer_map failed with %d\n", kr);
272 		if (is_restore() || bsd_rooted_ramdisk() || is_recovery_environment()) {
273 			// Don't fail boot here. Fail the upcalls that try to use the sharemem buffer instead.
274 			// This is to prevent panic during boot-time when xnu-proxy was initialized before StorageExclave
275 			// This can be reverted once Storage switched to V2
276 			storage_resource = NULL;
277 			kr = KERN_SUCCESS;
278 		}
279 	} else {
280 		use_shared_mem_vers = 1;
281 		exclaves_debug_printf(show_storage_upcalls,
282 		    "[storage_upcalls] Using legacy SharedMemory segment for IO");
283 	}
284 
285 	return kr;
286 }
287 EXCLAVES_BOOT_TASK(exclaves_storage_init, EXCLAVES_BOOT_RANK_SECOND);
288 
289 static int
290 storage_resource_io(exclaves_resource_t *resource, off_t offset,
291     size_t len, int (^cb)(char *, size_t))
292 {
293 	if (resource == NULL) {
294 		return ENOMEM;
295 	}
296 
297 	switch (use_shared_mem_vers) {
298 	case 1:
299 		return exclaves_named_buffer_io(resource, offset, len, cb);
300 	case 2:
301 		return exclaves_resource_shared_memory_io(resource, offset, len, cb);
302 	default:
303 		return ENOMEM;
304 	}
305 }
306 
307 tb_error_t
308 exclaves_storage_upcall_read(const enum xnuupcalls_fstag_s fstag,
309     const uint64_t fileid, const struct xnuupcalls_iodesc_s *descriptor,
310     tb_error_t (^completion)(xnuupcalls_xnuupcalls_read__result_s))
311 {
312 	exclaves_debug_printf(show_storage_upcalls, "[storage_upcalls_server] "
313 	    "read %d %lld %lld %lld %lld\n", fstag, fileid, descriptor->buf,
314 	    descriptor->fileoffset, descriptor->length);
315 	int error;
316 
317 	xnuupcalls_xnuupcalls_read__result_s result = {};
318 
319 	if (!storage_resource) {
320 		exclaves_debug_printf(show_errors,
321 		    "[storage_upcalls] shared memory buffer not initialized\n");
322 		xnuupcalls_xnuupcalls_read__result_init_failure(&result, ENOMEM);
323 		return completion(result);
324 	}
325 
326 	error = verify_storage_buf_offset(descriptor->buf, descriptor->length);
327 	if (error != 0) {
328 		xnuupcalls_xnuupcalls_read__result_init_failure(&result, error);
329 		return completion(result);
330 	}
331 
332 	__block uint64_t off = descriptor->fileoffset;
333 	error = storage_resource_io(storage_resource, descriptor->buf,
334 	    descriptor->length, ^(char *buffer, size_t size) {
335 		int ret = vfs_exclave_fs_read((uint32_t)fstag,
336 		fileid, off, size, buffer);
337 		off += size;
338 		return ret;
339 	});
340 
341 	if (error) {
342 		exclaves_debug_printf(show_errors, "[storage_upcalls_server] "
343 		    "read %d %lld %lld %lld %lld failed with errno %d",
344 		    fstag, fileid, descriptor->buf,
345 		    descriptor->fileoffset, descriptor->length, error);
346 		xnuupcalls_xnuupcalls_read__result_init_failure(&result, error);
347 	} else {
348 		exclaves_debug_printf(show_storage_upcalls,
349 		    "[storage_upcalls_server] vfs_exclave_fs_read succeeded\n");
350 		xnuupcalls_xnuupcalls_read__result_init_success(&result);
351 	}
352 
353 	return completion(result);
354 }
355 
356 tb_error_t
357 exclaves_storage_upcall_write(const enum xnuupcalls_fstag_s fstag,
358     const uint64_t fileid, const struct xnuupcalls_iodesc_s *descriptor,
359     tb_error_t (^completion)(xnuupcalls_xnuupcalls_write__result_s))
360 {
361 	exclaves_debug_printf(show_storage_upcalls, "[storage_upcalls_server] "
362 	    "write %d %lld %lld %lld %lld\n", fstag, fileid, descriptor->buf,
363 	    descriptor->fileoffset, descriptor->length);
364 	int error;
365 
366 	xnuupcalls_xnuupcalls_write__result_s result = {};
367 
368 	if (!storage_resource) {
369 		exclaves_debug_printf(show_errors,
370 		    "[storage_upcalls] shared memory buffer not initialized\n");
371 		xnuupcalls_xnuupcalls_write__result_init_failure(&result, ENOMEM);
372 		return completion(result);
373 	}
374 
375 	error = verify_storage_buf_offset(descriptor->buf, descriptor->length);
376 	if (error != 0) {
377 		xnuupcalls_xnuupcalls_write__result_init_failure(&result, error);
378 		return completion(result);
379 	}
380 
381 
382 	__block uint64_t off = descriptor->fileoffset;
383 	error = storage_resource_io(storage_resource, descriptor->buf,
384 	    descriptor->length, ^(char *buffer, size_t size) {
385 		int ret = vfs_exclave_fs_write((uint32_t)fstag,
386 		fileid, off, size, buffer);
387 		off += size;
388 		return ret;
389 	});
390 
391 	if (error) {
392 		exclaves_debug_printf(show_errors, "[storage_upcalls_server] "
393 		    "write %d %lld %lld %lld %lld failed with errno %d\n",
394 		    fstag, fileid, descriptor->buf, descriptor->fileoffset,
395 		    descriptor->length, error);
396 		xnuupcalls_xnuupcalls_write__result_init_failure(&result, error);
397 	} else {
398 		exclaves_debug_printf(show_storage_upcalls,
399 		    "[storage_upcalls_server] vfs_exclave_fs_write succeeded\n");
400 		xnuupcalls_xnuupcalls_write__result_init_success(&result);
401 	}
402 
403 	return completion(result);
404 }
405 
406 tb_error_t
407 exclaves_storage_upcall_remove(const enum xnuupcalls_fstag_s fstag,
408     const uint64_t rootid, const uint8_t name[_Nonnull 256],
409     tb_error_t (^completion)(xnuupcalls_xnuupcalls_remove__result_s))
410 {
411 	exclaves_debug_printf(show_storage_upcalls, "[storage_upcalls_server] "
412 	    "remove %d %lld %s\n", fstag, rootid, name);
413 	int error;
414 	xnuupcalls_xnuupcalls_remove__result_s result = {};
415 
416 	if ((error = verify_string_length((const char *)&name[0], 256))) {
417 		xnuupcalls_xnuupcalls_remove__result_init_failure(&result, error);
418 		return completion(result);
419 	}
420 	error = vfs_exclave_fs_remove((uint32_t)fstag, rootid,
421 	    (const char *)&name[0]);
422 	if (error) {
423 		exclaves_debug_printf(show_errors,
424 		    "[storage_upcalls_server] vfs_exclave_fs_remove failed with "
425 		    "%d\n", error);
426 		xnuupcalls_xnuupcalls_remove__result_init_failure(&result, error);
427 	} else {
428 		exclaves_debug_printf(show_storage_upcalls,
429 		    "[storage_upcalls_server] vfs_exclave_fs_remove succeeded\n");
430 		xnuupcalls_xnuupcalls_remove__result_init_success(&result);
431 	}
432 
433 	return completion(result);
434 }
435 
436 tb_error_t
437 exclaves_storage_upcall_sync(const enum xnuupcalls_fstag_s fstag,
438     const enum xnuupcalls_syncop_s op,
439     const uint64_t fileid, tb_error_t (^completion)(xnuupcalls_xnuupcalls_sync__result_s))
440 {
441 	exclaves_debug_printf(show_storage_upcalls, "[storage_upcalls_server] "
442 	    "sync %d %lld %d\n", fstag, fileid, (int)op);
443 	int error;
444 	xnuupcalls_xnuupcalls_sync__result_s result = {};
445 
446 	error = vfs_exclave_fs_sync((uint32_t)fstag, fileid, op);
447 	if (error) {
448 		exclaves_debug_printf(show_errors,
449 		    "[storage_upcalls_server] vfs_exclave_fs_sync failed with %d\n",
450 		    error);
451 		xnuupcalls_xnuupcalls_sync__result_init_failure(&result, error);
452 	} else {
453 		exclaves_debug_printf(show_storage_upcalls,
454 		    "[storage_upcalls_server] vfs_exclave_fs_sync succeeded\n");
455 		xnuupcalls_xnuupcalls_sync__result_init_success(&result);
456 	}
457 
458 	return completion(result);
459 }
460 
461 tb_error_t
462 exclaves_storage_upcall_readdir(const enum xnuupcalls_fstag_s fstag,
463     const uint64_t fileid, const uint64_t buf,
464     const uint32_t length, tb_error_t (^completion)(xnuupcalls_xnuupcalls_readdir__result_s))
465 {
466 	exclaves_debug_printf(show_storage_upcalls,
467 	    "[storage_upcalls_server] readdir %d %lld %lld %d\n",
468 	    fstag, fileid, buf, length);
469 	int error;
470 	int32_t count;
471 
472 	xnuupcalls_xnuupcalls_readdir__result_s result = {};
473 
474 	if (!storage_resource) {
475 		exclaves_debug_printf(show_errors,
476 		    "[storage_upcalls] shared memory buffer not initialized\n");
477 		xnuupcalls_xnuupcalls_readdir__result_init_failure(&result, ENOMEM);
478 		return completion(result);
479 	}
480 
481 	if ((error = verify_storage_buf_offset(buf, length))) {
482 		xnuupcalls_xnuupcalls_readdir__result_init_failure(&result, error);
483 		return completion(result);
484 	}
485 
486 	/*
487 	 * When we are able to map exclaves shared memory into kernel
488 	 * virtual address space, this temporary buffer will no longer
489 	 * be required.
490 	 */
491 	char *tmpbuf = kalloc_data(length, Z_WAITOK | Z_ZERO | Z_NOFAIL);
492 	error = vfs_exclave_fs_readdir((uint32_t)fstag, fileid,
493 	    tmpbuf, length, &count);
494 	assert3u(error, ==, 0);
495 
496 	__block char *p = tmpbuf;
497 	error = storage_resource_io(storage_resource, buf, length,
498 	    ^(char *buffer, size_t size) {
499 		memcpy(buffer, p, size);
500 		p += size;
501 		return 0;
502 	});
503 	assert3u(error, ==, 0);
504 	kfree_data(tmpbuf, length);
505 
506 	if (error) {
507 		exclaves_debug_printf(show_errors, "[storage_upcalls_server] "
508 		    "readdir %d %lld %lld %d failed with errno %d\n",
509 		    fstag, fileid, buf, length, error);
510 		xnuupcalls_xnuupcalls_readdir__result_init_failure(&result, error);
511 	} else {
512 		exclaves_debug_printf(show_storage_upcalls,
513 		    "[storage_upcalls_server] vfs_exclave_fs_readdir succeeded\n");
514 		xnuupcalls_xnuupcalls_readdir__result_init_success(&result, count);
515 	}
516 
517 	return completion(result);
518 }
519 
520 tb_error_t
521 exclaves_storage_upcall_getsize(const enum xnuupcalls_fstag_s fstag,
522     const uint64_t fileid,
523     tb_error_t (^completion)(xnuupcalls_xnuupcalls_getsize__result_s result))
524 {
525 	exclaves_debug_printf(show_storage_upcalls,
526 	    "[storage_upcalls_server] getsize %d %lld\n",
527 	    fstag, fileid);
528 	int error;
529 	uint64_t size;
530 	xnuupcalls_xnuupcalls_getsize__result_s result = {};
531 
532 	error = vfs_exclave_fs_getsize((uint32_t)fstag, fileid, &size);
533 	if (error) {
534 		exclaves_debug_printf(show_errors,
535 		    "[storage_upcalls_server] vfs_exclave_fs_getsize(%d, %lld) "
536 		    "failed with %d\n", fstag, fileid, error);
537 		xnuupcalls_xnuupcalls_getsize__result_init_failure(&result, error);
538 	} else {
539 		exclaves_debug_printf(show_storage_upcalls,
540 		    "[storage_upcalls_server] vfs_exclave_fs_getsize succeeded\n");
541 		xnuupcalls_xnuupcalls_getsize__result_init_success(&result, size);
542 	}
543 
544 	return completion(result);
545 }
546 
547 tb_error_t
548 exclaves_storage_upcall_sealstate(const enum xnuupcalls_fstag_s fstag,
549     tb_error_t (^completion)(xnuupcalls_xnuupcalls_sealstate__result_s result))
550 {
551 	exclaves_debug_printf(show_storage_upcalls,
552 	    "[storage_upcalls_server] sealstate %d\n",
553 	    fstag);
554 	int error;
555 	bool sealed;
556 	xnuupcalls_xnuupcalls_sealstate__result_s result = {};
557 
558 	error = vfs_exclave_fs_sealstate((uint32_t)fstag, &sealed);
559 	if (error) {
560 		exclaves_debug_printf(show_errors,
561 		    "[storage_upcalls_server] vfs_exclave_fs_sealstate(%d) "
562 		    "failed with %d\n", fstag, error);
563 		xnuupcalls_xnuupcalls_sealstate__result_init_failure(&result, error);
564 	} else {
565 		exclaves_debug_printf(show_storage_upcalls,
566 		    "[storage_upcalls_server] vfs_exclave_fs_sealstate succeeded\n");
567 		xnuupcalls_xnuupcalls_sealstate__result_init_success(&result, sealed);
568 	}
569 
570 	return completion(result);
571 }
572 
573 #endif /* __has_include(<Tightbeam/tightbeam.h>) */
574 
575 #endif /* CONFIG_EXCLAVES */
576