xref: /xnu-8020.121.3/bsd/vfs/vfs_cprotect.c (revision fdd8201d7b966f0c3ea610489d29bd841d358941)
1 /*
2  * Copyright (c) 2015-2018 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 #include <sys/cprotect.h>
30 #include <sys/malloc.h>
31 #include <sys/mount_internal.h>
32 #include <sys/filio.h>
33 #include <sys/content_protection.h>
34 #include <libkern/crypto/sha1.h>
35 #include <libkern/libkern.h>
36 //for write protection
37 #include <vm/vm_kern.h>
38 #include <vm/vm_map.h>
39 
40 #define PTR_ADD(type, base, offset)             (type)((uintptr_t)(base) + (offset))
41 
42 // -- struct cpx --
43 
44 /*
45  * This structure contains the unwrapped key and is passed to the lower layers.
46  * It is private so users must use the accessors declared in sys/cprotect.h
47  * to read/write it.
48  */
49 
50 // cpx_flags defined in cprotect.h
51 enum {
52 	CPX_SEP_WRAPPEDKEY                      = 0x01,
53 	CPX_IV_AES_CTX_INITIALIZED      = 0x02,
54 	CPX_USE_OFFSET_FOR_IV           = 0x04,
55 
56 	// Using AES IV context generated from key
57 	CPX_IV_AES_CTX_VFS                      = 0x08,
58 	CPX_SYNTHETIC_OFFSET_FOR_IV = 0x10,
59 	CPX_COMPOSITEKEY            = 0x20,
60 
61 	//write page protection
62 	CPX_WRITE_PROTECTABLE           = 0x40
63 };
64 
65 /*
66  * variable-length CPX structure. See fixed-length variant in cprotect.h
67  */
68 struct cpx {
69 #if DEBUG
70 	uint32_t                cpx_magic1;
71 #endif
72 	aes_encrypt_ctx         *cpx_iv_aes_ctx_ptr;// Pointer to context used for generating the IV
73 	cpx_flags_t             cpx_flags;
74 	uint16_t                cpx_max_key_len;
75 	uint16_t                cpx_key_len;
76 	//fixed length up to here.  cpx_cached_key is variable-length
77 	uint8_t                 cpx_cached_key[];
78 };
79 
80 /* Allows us to switch between CPX types */
81 typedef union cpxunion {
82 	struct cpx cpx_var;
83 	fcpx_t cpx_fixed;
84 } cpxunion_t;
85 
86 ZONE_DEFINE(cpx_zone, "cpx",
87     sizeof(struct fcpx), ZC_ZFREE_CLEARMEM);
88 ZONE_DEFINE(aes_ctz_zone, "AES ctx",
89     sizeof(aes_encrypt_ctx), ZC_ZFREE_CLEARMEM);
90 
91 // Note: see struct fcpx defined in sys/cprotect.h
92 
93 // -- cpx_t accessors --
94 
95 size_t
cpx_size(size_t key_len)96 cpx_size(size_t key_len)
97 {
98 	// This should pick up the 'magic' word in DEBUG for free.
99 	size_t size = sizeof(struct cpx) + key_len;
100 
101 	return size;
102 }
103 
104 size_t
cpx_sizex(const struct cpx * cpx)105 cpx_sizex(const struct cpx *cpx)
106 {
107 	return cpx_size(cpx->cpx_max_key_len);
108 }
109 
110 cpx_t
cpx_alloc(size_t key_len,bool needs_ctx)111 cpx_alloc(size_t key_len, bool needs_ctx)
112 {
113 	cpx_t cpx = NULL;
114 
115 #if CONFIG_KEYPAGE_WP
116 	/*
117 	 * Macs only use 1 key per volume, so force it into its own page.
118 	 * This way, we can write-protect as needed.
119 	 */
120 	size_t cpsize = cpx_size(key_len);
121 
122 	// silence warning for needs_ctx
123 	(void) needs_ctx;
124 
125 	if (cpsize < PAGE_SIZE) {
126 		/*
127 		 * Don't use MALLOC to allocate the page-sized structure.  Instead,
128 		 * use kmem_alloc to bypass KASAN since we are supplying our own
129 		 * unilateral write protection on this page. Note that kmem_alloc
130 		 * can block.
131 		 */
132 		if (kmem_alloc(kernel_map, (vm_offset_t *)&cpx, PAGE_SIZE,
133 		    KMA_DATA, VM_KERN_MEMORY_FILE)) {
134 			/*
135 			 * returning NULL at this point (due to failed
136 			 * allocation) would just result in a panic.
137 			 *
138 			 * fall back to attempting a normal kalloc, and don't
139 			 * let the cpx get marked PROTECTABLE.
140 			 */
141 			cpx = kheap_alloc(KHEAP_DEFAULT, cpx_size(key_len), Z_WAITOK);
142 		} else {
143 			//mark the page as protectable, since kmem_alloc succeeded.
144 			cpx->cpx_flags |= CPX_WRITE_PROTECTABLE;
145 		}
146 	} else {
147 		panic("cpx_size too large ! (%lu)", cpsize);
148 	}
149 #else
150 	/* If key page write protection disabled, just switch to zalloc */
151 
152 	// error out if you try to request a key that's too big
153 	if (key_len > VFS_CP_MAX_CACHEBUFLEN) {
154 		return NULL;
155 	}
156 
157 	// the actual key array is fixed-length, but the amount of usable content can vary, via 'key_len'
158 	cpx = zalloc_flags(cpx_zone, Z_WAITOK | Z_ZERO);
159 
160 	// if our encryption type needs it, alloc the context
161 	if (needs_ctx) {
162 		cpx_alloc_ctx(cpx);
163 	}
164 
165 #endif
166 	cpx_init(cpx, key_len);
167 
168 	return cpx;
169 }
170 
171 int
cpx_alloc_ctx(cpx_t cpx)172 cpx_alloc_ctx(cpx_t cpx)
173 {
174 #if CONFIG_KEYPAGE_WP
175 	(void) cpx;
176 #else
177 	if (cpx->cpx_iv_aes_ctx_ptr) {
178 		// already allocated?
179 		return 0;
180 	}
181 
182 	cpx->cpx_iv_aes_ctx_ptr = zalloc_flags(aes_ctz_zone, Z_WAITOK | Z_ZERO);
183 #endif // CONFIG_KEYPAGE_WP
184 
185 	return 0;
186 }
187 
188 void
cpx_free_ctx(cpx_t cpx)189 cpx_free_ctx(cpx_t cpx)
190 {
191 #if CONFIG_KEYPAGE_WP
192 	(void) cpx;
193 # else
194 	if (cpx->cpx_iv_aes_ctx_ptr) {
195 		zfree(aes_ctz_zone, cpx->cpx_iv_aes_ctx_ptr);
196 	}
197 #endif // CONFIG_KEYPAGE_WP
198 }
199 
200 void
cpx_writeprotect(cpx_t cpx)201 cpx_writeprotect(cpx_t cpx)
202 {
203 #if CONFIG_KEYPAGE_WP
204 	void *cpxstart = (void*)cpx;
205 	void *cpxend = (void*)((uint8_t*)cpx + PAGE_SIZE);
206 	if (cpx->cpx_flags & CPX_WRITE_PROTECTABLE) {
207 		vm_map_protect(kernel_map, (vm_map_offset_t)cpxstart, (vm_map_offset_t)cpxend, (VM_PROT_READ), FALSE);
208 	}
209 #else
210 	(void) cpx;
211 #endif
212 	return;
213 }
214 
215 #if DEBUG
216 static const uint32_t cpx_magic1 = 0x7b787063;          // cpx{
217 static const uint32_t cpx_magic2 = 0x7870637d;          // }cpx
218 #endif
219 
220 void
cpx_free(cpx_t cpx)221 cpx_free(cpx_t cpx)
222 {
223 #if DEBUG
224 	assert(cpx->cpx_magic1 == cpx_magic1);
225 	assert(*PTR_ADD(uint32_t *, cpx, cpx_sizex(cpx) - 4) == cpx_magic2);
226 #endif
227 
228 #if CONFIG_KEYPAGE_WP
229 	/* unprotect the page before bzeroing */
230 	void *cpxstart = (void*)cpx;
231 	void *cpxend = (void*)((uint8_t*)cpx + PAGE_SIZE);
232 	if (cpx->cpx_flags & CPX_WRITE_PROTECTABLE) {
233 		vm_map_protect(kernel_map, (vm_map_offset_t)cpxstart, (vm_map_offset_t)cpxend, (VM_PROT_DEFAULT), FALSE);
234 
235 		//now zero the memory after un-protecting it
236 		bzero(cpx->cpx_cached_key, cpx->cpx_max_key_len);
237 
238 		//If we are here, then we used kmem_alloc to get the page. Must use kmem_free to drop it.
239 		kmem_free(kernel_map, (vm_offset_t)cpx, PAGE_SIZE);
240 		return;
241 	}
242 #else
243 	// free the context if it wasn't already freed
244 	cpx_free_ctx(cpx);
245 	zfree(cpx_zone, cpx);
246 	return;
247 #endif
248 }
249 
250 void
cpx_init(cpx_t cpx,size_t key_len)251 cpx_init(cpx_t cpx, size_t key_len)
252 {
253 #if DEBUG
254 	cpx->cpx_magic1 = cpx_magic1;
255 	*PTR_ADD(uint32_t *, cpx, cpx_size(key_len) - 4) = cpx_magic2;
256 #endif
257 	cpx->cpx_flags = 0;
258 	cpx->cpx_key_len = 0;
259 	assert(key_len <= UINT16_MAX);
260 	cpx->cpx_max_key_len = (uint16_t)key_len;
261 }
262 
263 bool
cpx_is_sep_wrapped_key(const struct cpx * cpx)264 cpx_is_sep_wrapped_key(const struct cpx *cpx)
265 {
266 	return ISSET(cpx->cpx_flags, CPX_SEP_WRAPPEDKEY);
267 }
268 
269 void
cpx_set_is_sep_wrapped_key(struct cpx * cpx,bool v)270 cpx_set_is_sep_wrapped_key(struct cpx *cpx, bool v)
271 {
272 	if (v) {
273 		SET(cpx->cpx_flags, CPX_SEP_WRAPPEDKEY);
274 	} else {
275 		CLR(cpx->cpx_flags, CPX_SEP_WRAPPEDKEY);
276 	}
277 }
278 
279 bool
cpx_is_composite_key(const struct cpx * cpx)280 cpx_is_composite_key(const struct cpx *cpx)
281 {
282 	return ISSET(cpx->cpx_flags, CPX_COMPOSITEKEY);
283 }
284 
285 void
cpx_set_is_composite_key(struct cpx * cpx,bool v)286 cpx_set_is_composite_key(struct cpx *cpx, bool v)
287 {
288 	if (v) {
289 		SET(cpx->cpx_flags, CPX_COMPOSITEKEY);
290 	} else {
291 		CLR(cpx->cpx_flags, CPX_COMPOSITEKEY);
292 	}
293 }
294 
295 bool
cpx_use_offset_for_iv(const struct cpx * cpx)296 cpx_use_offset_for_iv(const struct cpx *cpx)
297 {
298 	return ISSET(cpx->cpx_flags, CPX_USE_OFFSET_FOR_IV);
299 }
300 
301 void
cpx_set_use_offset_for_iv(struct cpx * cpx,bool v)302 cpx_set_use_offset_for_iv(struct cpx *cpx, bool v)
303 {
304 	if (v) {
305 		SET(cpx->cpx_flags, CPX_USE_OFFSET_FOR_IV);
306 	} else {
307 		CLR(cpx->cpx_flags, CPX_USE_OFFSET_FOR_IV);
308 	}
309 }
310 
311 bool
cpx_synthetic_offset_for_iv(const struct cpx * cpx)312 cpx_synthetic_offset_for_iv(const struct cpx *cpx)
313 {
314 	return ISSET(cpx->cpx_flags, CPX_SYNTHETIC_OFFSET_FOR_IV);
315 }
316 
317 void
cpx_set_synthetic_offset_for_iv(struct cpx * cpx,bool v)318 cpx_set_synthetic_offset_for_iv(struct cpx *cpx, bool v)
319 {
320 	if (v) {
321 		SET(cpx->cpx_flags, CPX_SYNTHETIC_OFFSET_FOR_IV);
322 	} else {
323 		CLR(cpx->cpx_flags, CPX_SYNTHETIC_OFFSET_FOR_IV);
324 	}
325 }
326 
327 uint16_t
cpx_max_key_len(const struct cpx * cpx)328 cpx_max_key_len(const struct cpx *cpx)
329 {
330 	return cpx->cpx_max_key_len;
331 }
332 
333 uint16_t
cpx_key_len(const struct cpx * cpx)334 cpx_key_len(const struct cpx *cpx)
335 {
336 	return cpx->cpx_key_len;
337 }
338 
339 void
cpx_set_key_len(struct cpx * cpx,uint16_t key_len)340 cpx_set_key_len(struct cpx *cpx, uint16_t key_len)
341 {
342 	cpx->cpx_key_len = key_len;
343 
344 	if (ISSET(cpx->cpx_flags, CPX_IV_AES_CTX_VFS)) {
345 		/*
346 		 * We assume that if the key length is being modified, the key
347 		 * has changed.  As a result, un-set any bits related to the
348 		 * AES context, if needed. They should be re-generated
349 		 * on-demand.
350 		 */
351 		CLR(cpx->cpx_flags, CPX_IV_AES_CTX_INITIALIZED | CPX_IV_AES_CTX_VFS);
352 	}
353 }
354 
355 bool
cpx_has_key(const struct cpx * cpx)356 cpx_has_key(const struct cpx *cpx)
357 {
358 	return cpx->cpx_key_len > 0;
359 }
360 
361 #pragma clang diagnostic push
362 #pragma clang diagnostic ignored "-Wcast-qual"
363 void *
cpx_key(const struct cpx * cpx)364 cpx_key(const struct cpx *cpx)
365 {
366 	return (void *)cpx->cpx_cached_key;
367 }
368 #pragma clang diagnostic pop
369 
370 void
cpx_set_aes_iv_key(struct cpx * cpx,void * iv_key)371 cpx_set_aes_iv_key(struct cpx *cpx, void *iv_key)
372 {
373 	if (cpx->cpx_iv_aes_ctx_ptr) {
374 		aes_encrypt_key128(iv_key, cpx->cpx_iv_aes_ctx_ptr);
375 		SET(cpx->cpx_flags, CPX_IV_AES_CTX_INITIALIZED | CPX_USE_OFFSET_FOR_IV);
376 		CLR(cpx->cpx_flags, CPX_IV_AES_CTX_VFS);
377 	}
378 }
379 
380 aes_encrypt_ctx *
cpx_iv_aes_ctx(struct cpx * cpx)381 cpx_iv_aes_ctx(struct cpx *cpx)
382 {
383 	if (ISSET(cpx->cpx_flags, CPX_IV_AES_CTX_INITIALIZED)) {
384 		return cpx->cpx_iv_aes_ctx_ptr;
385 	}
386 
387 	SHA1_CTX sha1ctxt;
388 	uint8_t digest[SHA_DIGEST_LENGTH]; /* Kiv */
389 
390 	/* First init the cp_cache_iv_key[] */
391 	SHA1Init(&sha1ctxt);
392 
393 	/*
394 	 * We can only use this when the keys are generated in the AP; As a result
395 	 * we only use the first 32 bytes of key length in the cache key
396 	 */
397 	SHA1Update(&sha1ctxt, cpx->cpx_cached_key, cpx->cpx_key_len);
398 	SHA1Final(digest, &sha1ctxt);
399 
400 	cpx_set_aes_iv_key(cpx, digest);
401 	SET(cpx->cpx_flags, CPX_IV_AES_CTX_VFS);
402 
403 	return cpx->cpx_iv_aes_ctx_ptr;
404 }
405 
406 void
cpx_flush(cpx_t cpx)407 cpx_flush(cpx_t cpx)
408 {
409 	bzero(cpx->cpx_cached_key, cpx->cpx_max_key_len);
410 	if (cpx->cpx_iv_aes_ctx_ptr) {
411 		bzero(cpx->cpx_iv_aes_ctx_ptr, sizeof(aes_encrypt_ctx));
412 	}
413 	cpx->cpx_flags = 0;
414 	cpx->cpx_key_len = 0;
415 }
416 
417 bool
cpx_can_copy(const struct cpx * src,const struct cpx * dst)418 cpx_can_copy(const struct cpx *src, const struct cpx *dst)
419 {
420 	return src->cpx_key_len <= dst->cpx_max_key_len;
421 }
422 
423 void
cpx_copy(const struct cpx * src,cpx_t dst)424 cpx_copy(const struct cpx *src, cpx_t dst)
425 {
426 	uint16_t key_len = cpx_key_len(src);
427 	cpx_set_key_len(dst, key_len);
428 	memcpy(cpx_key(dst), cpx_key(src), key_len);
429 	dst->cpx_flags = src->cpx_flags;
430 	if (ISSET(dst->cpx_flags, CPX_IV_AES_CTX_INITIALIZED)) {
431 		*(dst->cpx_iv_aes_ctx_ptr) = *(src->cpx_iv_aes_ctx_ptr); // deep copy
432 	}
433 }
434 
435 typedef struct {
436 	cp_lock_state_t state;
437 	int             valid_uuid;
438 	uuid_t          volume_uuid;
439 } cp_lock_vfs_callback_arg;
440 
441 static int
cp_lock_vfs_callback(mount_t mp,void * arg)442 cp_lock_vfs_callback(mount_t mp, void *arg)
443 {
444 	cp_lock_vfs_callback_arg *callback_arg = (cp_lock_vfs_callback_arg *)arg;
445 
446 	if (callback_arg->valid_uuid) {
447 		struct vfs_attr va;
448 		VFSATTR_INIT(&va);
449 		VFSATTR_WANTED(&va, f_uuid);
450 
451 		if (vfs_getattr(mp, &va, vfs_context_current())) {
452 			return 0;
453 		}
454 
455 		if (!VFSATTR_IS_SUPPORTED(&va, f_uuid)) {
456 			return 0;
457 		}
458 
459 		if (memcmp(va.f_uuid, callback_arg->volume_uuid, sizeof(uuid_t))) {
460 			return 0;
461 		}
462 	}
463 
464 	VFS_IOCTL(mp, FIODEVICELOCKED, (void *)(uintptr_t)callback_arg->state, 0, vfs_context_kernel());
465 	return 0;
466 }
467 
468 int
cp_key_store_action(cp_key_store_action_t action)469 cp_key_store_action(cp_key_store_action_t action)
470 {
471 	cp_lock_vfs_callback_arg callback_arg;
472 
473 	switch (action) {
474 	case CP_ACTION_LOCKED:
475 	case CP_ACTION_UNLOCKED:
476 		callback_arg.state = (action == CP_ACTION_LOCKED ? CP_LOCKED_STATE : CP_UNLOCKED_STATE);
477 		memset(callback_arg.volume_uuid, 0, sizeof(uuid_t));
478 		callback_arg.valid_uuid = 0;
479 		return vfs_iterate(0, cp_lock_vfs_callback, (void *)&callback_arg);
480 	default:
481 		return -1;
482 	}
483 }
484 
485 int
cp_key_store_action_for_volume(uuid_t volume_uuid,cp_key_store_action_t action)486 cp_key_store_action_for_volume(uuid_t volume_uuid, cp_key_store_action_t action)
487 {
488 	cp_lock_vfs_callback_arg callback_arg;
489 
490 	switch (action) {
491 	case CP_ACTION_LOCKED:
492 	case CP_ACTION_UNLOCKED:
493 		callback_arg.state = (action == CP_ACTION_LOCKED ? CP_LOCKED_STATE : CP_UNLOCKED_STATE);
494 		memcpy(callback_arg.volume_uuid, volume_uuid, sizeof(uuid_t));
495 		callback_arg.valid_uuid = 1;
496 		return vfs_iterate(0, cp_lock_vfs_callback, (void *)&callback_arg);
497 	default:
498 		return -1;
499 	}
500 }
501 
502 int
cp_is_valid_class(int isdir,int32_t protectionclass)503 cp_is_valid_class(int isdir, int32_t protectionclass)
504 {
505 	/*
506 	 * The valid protection classes are from 0 -> N
507 	 * We use a signed argument to detect unassigned values from
508 	 * directory entry creation time in HFS.
509 	 */
510 	if (isdir) {
511 		/* Directories are not allowed to have F, but they can have "NONE" */
512 		return (protectionclass >= PROTECTION_CLASS_DIR_NONE) &&
513 		       (protectionclass <= PROTECTION_CLASS_D);
514 	} else {
515 		return (protectionclass >= PROTECTION_CLASS_A) &&
516 		       (protectionclass <= PROTECTION_CLASS_F);
517 	}
518 }
519 
520 /*
521  * Parses versions of the form 12A316, i.e. <major><minor><revision> and
522  * returns a uint32_t in the form 0xaabbcccc where aa = <major>,
523  * bb = <ASCII char>, cccc = <revision>.
524  */
525 static cp_key_os_version_t
parse_os_version(const char * vers)526 parse_os_version(const char *vers)
527 {
528 	const char *p = vers;
529 
530 	int a = 0;
531 	while (*p >= '0' && *p <= '9') {
532 		a = a * 10 + *p - '0';
533 		++p;
534 	}
535 
536 	if (!a) {
537 		return 0;
538 	}
539 
540 	int b = *p++;
541 	if (!b) {
542 		return 0;
543 	}
544 
545 	int c = 0;
546 	while (*p >= '0' && *p <= '9') {
547 		c = c * 10 + *p - '0';
548 		++p;
549 	}
550 
551 	if (!c) {
552 		return 0;
553 	}
554 
555 	return (a & 0xff) << 24 | b << 16 | (c & 0xffff);
556 }
557 
558 cp_key_os_version_t
cp_os_version(void)559 cp_os_version(void)
560 {
561 	static cp_key_os_version_t cp_os_version;
562 
563 	if (cp_os_version) {
564 		return cp_os_version;
565 	}
566 
567 	if (!osversion[0]) {
568 		return 0;
569 	}
570 
571 	cp_os_version = parse_os_version(osversion);
572 	if (!cp_os_version) {
573 		printf("cp_os_version: unable to parse osversion `%s'\n", osversion);
574 		cp_os_version = 1;
575 	}
576 
577 	return cp_os_version;
578 }
579