]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_cprotect.c
xnu-4570.31.3.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_cprotect.c
1 /*
2 * Copyright (c) 2015 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
37 #define PTR_ADD(type, base, offset) (type)((uintptr_t)(base) + (offset))
38
39 // -- struct cpx --
40
41 /*
42 * This structure contains the unwrapped key and is passed to the lower layers.
43 * It is private so users must use the accessors declared in sys/cprotect.h
44 * to read/write it.
45 */
46
47 // cpx_flags
48 typedef uint32_t cpx_flags_t;
49 enum {
50 CPX_SEP_WRAPPEDKEY = 0x01,
51 CPX_IV_AES_CTX_INITIALIZED = 0x02,
52 CPX_USE_OFFSET_FOR_IV = 0x04,
53
54 // Using AES IV context generated from key
55 CPX_IV_AES_CTX_VFS = 0x08,
56 CPX_SYNTHETIC_OFFSET_FOR_IV = 0x10,
57 CPX_COMPOSITEKEY = 0x20
58 };
59
60 struct cpx {
61 #if DEBUG
62 uint32_t cpx_magic1;
63 #endif
64 aes_encrypt_ctx cpx_iv_aes_ctx; // Context used for generating the IV
65 cpx_flags_t cpx_flags;
66 uint16_t cpx_max_key_len;
67 uint16_t cpx_key_len;
68 uint8_t cpx_cached_key[];
69 };
70
71 // -- cpx_t accessors --
72
73 size_t cpx_size(size_t key_size)
74 {
75 size_t size = sizeof(struct cpx) + key_size;
76
77 #if DEBUG
78 size += 4; // Extra for magic
79 #endif
80
81 return size;
82 }
83
84 size_t cpx_sizex(const struct cpx *cpx)
85 {
86 return cpx_size(cpx->cpx_max_key_len);
87 }
88
89 cpx_t cpx_alloc(size_t key_len)
90 {
91 cpx_t cpx;
92
93 MALLOC(cpx, cpx_t, cpx_size(key_len), M_TEMP, M_WAITOK);
94
95 cpx_init(cpx, key_len);
96
97 return cpx;
98 }
99
100 #if DEBUG
101 static const uint32_t cpx_magic1 = 0x7b787063; // cpx{
102 static const uint32_t cpx_magic2 = 0x7870637d; // }cpx
103 #endif
104
105 void cpx_free(cpx_t cpx)
106 {
107 #if DEBUG
108 assert(cpx->cpx_magic1 == cpx_magic1);
109 assert(*PTR_ADD(uint32_t *, cpx, cpx_sizex(cpx) - 4) == cpx_magic2);
110 #endif
111 bzero(cpx->cpx_cached_key, cpx->cpx_max_key_len);
112 FREE(cpx, M_TEMP);
113 }
114
115 void cpx_init(cpx_t cpx, size_t key_len)
116 {
117 #if DEBUG
118 cpx->cpx_magic1 = cpx_magic1;
119 *PTR_ADD(uint32_t *, cpx, cpx_size(key_len) - 4) = cpx_magic2;
120 #endif
121 cpx->cpx_flags = 0;
122 cpx->cpx_key_len = 0;
123 cpx->cpx_max_key_len = key_len;
124 }
125
126 bool cpx_is_sep_wrapped_key(const struct cpx *cpx)
127 {
128 return ISSET(cpx->cpx_flags, CPX_SEP_WRAPPEDKEY);
129 }
130
131 void cpx_set_is_sep_wrapped_key(struct cpx *cpx, bool v)
132 {
133 if (v)
134 SET(cpx->cpx_flags, CPX_SEP_WRAPPEDKEY);
135 else
136 CLR(cpx->cpx_flags, CPX_SEP_WRAPPEDKEY);
137 }
138
139 bool cpx_is_composite_key(const struct cpx *cpx)
140 {
141 return ISSET(cpx->cpx_flags, CPX_COMPOSITEKEY);
142 }
143
144 void cpx_set_is_composite_key(struct cpx *cpx, bool v)
145 {
146 if (v)
147 SET(cpx->cpx_flags, CPX_COMPOSITEKEY);
148 else
149 CLR(cpx->cpx_flags, CPX_COMPOSITEKEY);
150 }
151
152 bool cpx_use_offset_for_iv(const struct cpx *cpx)
153 {
154 return ISSET(cpx->cpx_flags, CPX_USE_OFFSET_FOR_IV);
155 }
156
157 void cpx_set_use_offset_for_iv(struct cpx *cpx, bool v)
158 {
159 if (v)
160 SET(cpx->cpx_flags, CPX_USE_OFFSET_FOR_IV);
161 else
162 CLR(cpx->cpx_flags, CPX_USE_OFFSET_FOR_IV);
163 }
164
165 bool cpx_synthetic_offset_for_iv(const struct cpx *cpx)
166 {
167 return ISSET(cpx->cpx_flags, CPX_SYNTHETIC_OFFSET_FOR_IV);
168 }
169
170 void cpx_set_synthetic_offset_for_iv(struct cpx *cpx, bool v)
171 {
172 if (v)
173 SET(cpx->cpx_flags, CPX_SYNTHETIC_OFFSET_FOR_IV);
174 else
175 CLR(cpx->cpx_flags, CPX_SYNTHETIC_OFFSET_FOR_IV);
176 }
177
178 uint16_t cpx_max_key_len(const struct cpx *cpx)
179 {
180 return cpx->cpx_max_key_len;
181 }
182
183 uint16_t cpx_key_len(const struct cpx *cpx)
184 {
185 return cpx->cpx_key_len;
186 }
187
188 void cpx_set_key_len(struct cpx *cpx, uint16_t key_len)
189 {
190 cpx->cpx_key_len = key_len;
191
192 if (ISSET(cpx->cpx_flags, CPX_IV_AES_CTX_VFS)) {
193 /*
194 * We assume that if the key length is being modified, the key
195 * has changed. As a result, un-set any bits related to the
196 * AES context, if needed. They should be re-generated
197 * on-demand.
198 */
199 CLR(cpx->cpx_flags, CPX_IV_AES_CTX_INITIALIZED | CPX_IV_AES_CTX_VFS);
200 }
201 }
202
203 bool cpx_has_key(const struct cpx *cpx)
204 {
205 return cpx->cpx_key_len > 0;
206 }
207
208 #pragma clang diagnostic push
209 #pragma clang diagnostic ignored "-Wcast-qual"
210 void *cpx_key(const struct cpx *cpx)
211 {
212 return (void *)cpx->cpx_cached_key;
213 }
214 #pragma clang diagnostic pop
215
216 void cpx_set_aes_iv_key(struct cpx *cpx, void *iv_key)
217 {
218 aes_encrypt_key128(iv_key, &cpx->cpx_iv_aes_ctx);
219 SET(cpx->cpx_flags, CPX_IV_AES_CTX_INITIALIZED | CPX_USE_OFFSET_FOR_IV);
220 CLR(cpx->cpx_flags, CPX_IV_AES_CTX_VFS);
221 }
222
223 aes_encrypt_ctx *cpx_iv_aes_ctx(struct cpx *cpx)
224 {
225 if (ISSET(cpx->cpx_flags, CPX_IV_AES_CTX_INITIALIZED))
226 return &cpx->cpx_iv_aes_ctx;
227
228 SHA1_CTX sha1ctxt;
229 uint8_t digest[SHA_DIGEST_LENGTH]; /* Kiv */
230
231 /* First init the cp_cache_iv_key[] */
232 SHA1Init(&sha1ctxt);
233
234 /*
235 * We can only use this when the keys are generated in the AP; As a result
236 * we only use the first 32 bytes of key length in the cache key
237 */
238 SHA1Update(&sha1ctxt, cpx->cpx_cached_key, cpx->cpx_key_len);
239 SHA1Final(digest, &sha1ctxt);
240
241 cpx_set_aes_iv_key(cpx, digest);
242 SET(cpx->cpx_flags, CPX_IV_AES_CTX_VFS);
243
244 return &cpx->cpx_iv_aes_ctx;
245 }
246
247 void cpx_flush(cpx_t cpx)
248 {
249 bzero(cpx->cpx_cached_key, cpx->cpx_max_key_len);
250 bzero(&cpx->cpx_iv_aes_ctx, sizeof(cpx->cpx_iv_aes_ctx));
251 cpx->cpx_flags = 0;
252 cpx->cpx_key_len = 0;
253 }
254
255 bool cpx_can_copy(const struct cpx *src, const struct cpx *dst)
256 {
257 return src->cpx_key_len <= dst->cpx_max_key_len;
258 }
259
260 void cpx_copy(const struct cpx *src, cpx_t dst)
261 {
262 uint16_t key_len = cpx_key_len(src);
263 cpx_set_key_len(dst, key_len);
264 memcpy(cpx_key(dst), cpx_key(src), key_len);
265 dst->cpx_flags = src->cpx_flags;
266 if (ISSET(dst->cpx_flags, CPX_IV_AES_CTX_INITIALIZED))
267 dst->cpx_iv_aes_ctx = src->cpx_iv_aes_ctx;
268 }
269
270 typedef struct {
271 cp_lock_state_t state;
272 int valid_uuid;
273 uuid_t volume_uuid;
274 } cp_lock_vfs_callback_arg;
275
276 static int
277 cp_lock_vfs_callback(mount_t mp, void *arg)
278 {
279 cp_lock_vfs_callback_arg *callback_arg = (cp_lock_vfs_callback_arg *)arg;
280
281 if (callback_arg->valid_uuid) {
282 struct vfs_attr va;
283 VFSATTR_INIT(&va);
284 VFSATTR_WANTED(&va, f_uuid);
285
286 if (vfs_getattr(mp, &va, vfs_context_current()))
287 return 0;
288
289 if (!VFSATTR_IS_SUPPORTED(&va, f_uuid))
290 return 0;
291
292 if(memcmp(va.f_uuid, callback_arg->volume_uuid, sizeof(uuid_t)))
293 return 0;
294 }
295
296 VFS_IOCTL(mp, FIODEVICELOCKED, (void *)(uintptr_t)callback_arg->state, 0, vfs_context_kernel());
297 return 0;
298 }
299
300 int
301 cp_key_store_action(cp_key_store_action_t action)
302 {
303 cp_lock_vfs_callback_arg callback_arg;
304
305 switch (action) {
306 case CP_ACTION_LOCKED:
307 case CP_ACTION_UNLOCKED:
308 callback_arg.state = (action == CP_ACTION_LOCKED ? CP_LOCKED_STATE : CP_UNLOCKED_STATE);
309 memset(callback_arg.volume_uuid, 0, sizeof(uuid_t));
310 callback_arg.valid_uuid = 0;
311 return vfs_iterate(0, cp_lock_vfs_callback, (void *)&callback_arg);
312 default:
313 return -1;
314 }
315 }
316
317 int
318 cp_key_store_action_for_volume(uuid_t volume_uuid, cp_key_store_action_t action)
319 {
320 cp_lock_vfs_callback_arg callback_arg;
321
322 switch (action) {
323 case CP_ACTION_LOCKED:
324 case CP_ACTION_UNLOCKED:
325 callback_arg.state = (action == CP_ACTION_LOCKED ? CP_LOCKED_STATE : CP_UNLOCKED_STATE);
326 memcpy(callback_arg.volume_uuid, volume_uuid, sizeof(uuid_t));
327 callback_arg.valid_uuid = 1;
328 return vfs_iterate(0, cp_lock_vfs_callback, (void *)&callback_arg);
329 default:
330 return -1;
331 }
332 }
333
334 int
335 cp_is_valid_class(int isdir, int32_t protectionclass)
336 {
337 /*
338 * The valid protection classes are from 0 -> N
339 * We use a signed argument to detect unassigned values from
340 * directory entry creation time in HFS.
341 */
342 if (isdir) {
343 /* Directories are not allowed to have F, but they can have "NONE" */
344 return ((protectionclass >= PROTECTION_CLASS_DIR_NONE) &&
345 (protectionclass <= PROTECTION_CLASS_D));
346 }
347 else {
348 return ((protectionclass >= PROTECTION_CLASS_A) &&
349 (protectionclass <= PROTECTION_CLASS_F));
350 }
351 }
352
353 /*
354 * Parses versions of the form 12A316, i.e. <major><minor><revision> and
355 * returns a uint32_t in the form 0xaabbcccc where aa = <major>,
356 * bb = <ASCII char>, cccc = <revision>.
357 */
358 static cp_key_os_version_t
359 parse_os_version(const char *vers)
360 {
361 const char *p = vers;
362
363 int a = 0;
364 while (*p >= '0' && *p <= '9') {
365 a = a * 10 + *p - '0';
366 ++p;
367 }
368
369 if (!a)
370 return 0;
371
372 int b = *p++;
373 if (!b)
374 return 0;
375
376 int c = 0;
377 while (*p >= '0' && *p <= '9') {
378 c = c * 10 + *p - '0';
379 ++p;
380 }
381
382 if (!c)
383 return 0;
384
385 return (a & 0xff) << 24 | b << 16 | (c & 0xffff);
386 }
387
388 cp_key_os_version_t
389 cp_os_version(void)
390 {
391 static cp_key_os_version_t cp_os_version;
392
393 if (cp_os_version)
394 return cp_os_version;
395
396 if (!osversion[0])
397 return 0;
398
399 cp_os_version = parse_os_version(osversion);
400 if (!cp_os_version) {
401 printf("cp_os_version: unable to parse osversion `%s'\n", osversion);
402 cp_os_version = 1;
403 }
404
405 return cp_os_version;
406 }