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