1 /*
2 * Copyright (c) 1999-2020 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 * File: ubc_subr.c
30 * Author: Umesh Vaishampayan [[email protected]]
31 * 05-Aug-1999 umeshv Created.
32 *
33 * Functions related to Unified Buffer cache.
34 *
35 * Caller of UBC functions MUST have a valid reference on the vnode.
36 *
37 */
38
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/lock.h>
43 #include <sys/mman.h>
44 #include <sys/mount_internal.h>
45 #include <sys/vnode_internal.h>
46 #include <sys/ubc_internal.h>
47 #include <sys/ucred.h>
48 #include <sys/proc_internal.h>
49 #include <sys/kauth.h>
50 #include <sys/buf.h>
51 #include <sys/user.h>
52 #include <sys/codesign.h>
53 #include <sys/codedir_internal.h>
54 #include <sys/fsevents.h>
55 #include <sys/fcntl.h>
56 #include <sys/reboot.h>
57
58 #include <mach/mach_types.h>
59 #include <mach/memory_object_types.h>
60 #include <mach/memory_object_control.h>
61 #include <mach/vm_map.h>
62 #include <mach/mach_vm.h>
63 #include <mach/upl.h>
64
65 #include <kern/kern_types.h>
66 #include <kern/kalloc.h>
67 #include <kern/zalloc.h>
68 #include <kern/thread.h>
69 #include <vm/pmap.h>
70 #include <vm/vm_kern.h>
71 #include <vm/vm_protos.h> /* last */
72
73 #include <libkern/crypto/sha1.h>
74 #include <libkern/crypto/sha2.h>
75 #include <libkern/libkern.h>
76
77 #include <security/mac_framework.h>
78 #include <stdbool.h>
79 #include <stdatomic.h>
80 #include <libkern/amfi/amfi.h>
81
82 /* XXX These should be in a BSD accessible Mach header, but aren't. */
83 extern kern_return_t memory_object_pages_resident(memory_object_control_t,
84 boolean_t *);
85 extern kern_return_t memory_object_signed(memory_object_control_t control,
86 boolean_t is_signed);
87 extern boolean_t memory_object_is_signed(memory_object_control_t);
88 extern void memory_object_mark_trusted(
89 memory_object_control_t control);
90
91 /* XXX Same for those. */
92
93 extern void Debugger(const char *message);
94
95 #if DIAGNOSTIC
96 #if defined(assert)
97 #undef assert
98 #endif
99 #define assert(cond) \
100 ((void) ((cond) ? 0 : panic("Assert failed: %s", # cond)))
101 #else
102 #include <kern/assert.h>
103 #endif /* DIAGNOSTIC */
104
105 static int ubc_info_init_internal(struct vnode *vp, int withfsize, off_t filesize);
106 static int ubc_umcallback(vnode_t, void *);
107 static int ubc_msync_internal(vnode_t, off_t, off_t, off_t *, int, int *);
108 static void ubc_cs_free(struct ubc_info *uip);
109
110 static boolean_t ubc_cs_supports_multilevel_hash(struct cs_blob *blob);
111 static kern_return_t ubc_cs_convert_to_multilevel_hash(struct cs_blob *blob);
112
113 ZONE_DEFINE_TYPE(ubc_info_zone, "ubc_info zone", struct ubc_info,
114 ZC_ZFREE_CLEARMEM);
115 static uint32_t cs_blob_generation_count = 1;
116
117 /*
118 * CODESIGNING
119 * Routines to navigate code signing data structures in the kernel...
120 */
121
122 ZONE_DEFINE_ID(ZONE_ID_CS_BLOB, "cs_blob zone", struct cs_blob,
123 ZC_READONLY | ZC_ZFREE_CLEARMEM);
124
125 extern int cs_debug;
126
127 #define PAGE_SHIFT_4K (12)
128
129 static boolean_t
cs_valid_range(const void * start,const void * end,const void * lower_bound,const void * upper_bound)130 cs_valid_range(
131 const void *start,
132 const void *end,
133 const void *lower_bound,
134 const void *upper_bound)
135 {
136 if (upper_bound < lower_bound ||
137 end < start) {
138 return FALSE;
139 }
140
141 if (start < lower_bound ||
142 end > upper_bound) {
143 return FALSE;
144 }
145
146 return TRUE;
147 }
148
149 typedef void (*cs_md_init)(void *ctx);
150 typedef void (*cs_md_update)(void *ctx, const void *data, size_t size);
151 typedef void (*cs_md_final)(void *hash, void *ctx);
152
153 struct cs_hash {
154 uint8_t cs_type; /* type code as per code signing */
155 size_t cs_size; /* size of effective hash (may be truncated) */
156 size_t cs_digest_size;/* size of native hash */
157 cs_md_init cs_init;
158 cs_md_update cs_update;
159 cs_md_final cs_final;
160 };
161
162 uint8_t
cs_hash_type(struct cs_hash const * const cs_hash)163 cs_hash_type(
164 struct cs_hash const * const cs_hash)
165 {
166 return cs_hash->cs_type;
167 }
168
169 static const struct cs_hash cs_hash_sha1 = {
170 .cs_type = CS_HASHTYPE_SHA1,
171 .cs_size = CS_SHA1_LEN,
172 .cs_digest_size = SHA_DIGEST_LENGTH,
173 .cs_init = (cs_md_init)SHA1Init,
174 .cs_update = (cs_md_update)SHA1Update,
175 .cs_final = (cs_md_final)SHA1Final,
176 };
177 #if CRYPTO_SHA2
178 static const struct cs_hash cs_hash_sha256 = {
179 .cs_type = CS_HASHTYPE_SHA256,
180 .cs_size = SHA256_DIGEST_LENGTH,
181 .cs_digest_size = SHA256_DIGEST_LENGTH,
182 .cs_init = (cs_md_init)SHA256_Init,
183 .cs_update = (cs_md_update)SHA256_Update,
184 .cs_final = (cs_md_final)SHA256_Final,
185 };
186 static const struct cs_hash cs_hash_sha256_truncate = {
187 .cs_type = CS_HASHTYPE_SHA256_TRUNCATED,
188 .cs_size = CS_SHA256_TRUNCATED_LEN,
189 .cs_digest_size = SHA256_DIGEST_LENGTH,
190 .cs_init = (cs_md_init)SHA256_Init,
191 .cs_update = (cs_md_update)SHA256_Update,
192 .cs_final = (cs_md_final)SHA256_Final,
193 };
194 static const struct cs_hash cs_hash_sha384 = {
195 .cs_type = CS_HASHTYPE_SHA384,
196 .cs_size = SHA384_DIGEST_LENGTH,
197 .cs_digest_size = SHA384_DIGEST_LENGTH,
198 .cs_init = (cs_md_init)SHA384_Init,
199 .cs_update = (cs_md_update)SHA384_Update,
200 .cs_final = (cs_md_final)SHA384_Final,
201 };
202 #endif
203
204 static struct cs_hash const *
cs_find_md(uint8_t type)205 cs_find_md(uint8_t type)
206 {
207 if (type == CS_HASHTYPE_SHA1) {
208 return &cs_hash_sha1;
209 #if CRYPTO_SHA2
210 } else if (type == CS_HASHTYPE_SHA256) {
211 return &cs_hash_sha256;
212 } else if (type == CS_HASHTYPE_SHA256_TRUNCATED) {
213 return &cs_hash_sha256_truncate;
214 } else if (type == CS_HASHTYPE_SHA384) {
215 return &cs_hash_sha384;
216 #endif
217 }
218 return NULL;
219 }
220
221 union cs_hash_union {
222 SHA1_CTX sha1ctxt;
223 SHA256_CTX sha256ctx;
224 SHA384_CTX sha384ctx;
225 };
226
227
228 /*
229 * Choose among different hash algorithms.
230 * Higher is better, 0 => don't use at all.
231 */
232 static const uint32_t hashPriorities[] = {
233 CS_HASHTYPE_SHA1,
234 CS_HASHTYPE_SHA256_TRUNCATED,
235 CS_HASHTYPE_SHA256,
236 CS_HASHTYPE_SHA384,
237 };
238
239 static unsigned int
hash_rank(const CS_CodeDirectory * cd)240 hash_rank(const CS_CodeDirectory *cd)
241 {
242 uint32_t type = cd->hashType;
243 unsigned int n;
244
245 for (n = 0; n < sizeof(hashPriorities) / sizeof(hashPriorities[0]); ++n) {
246 if (hashPriorities[n] == type) {
247 return n + 1;
248 }
249 }
250 return 0; /* not supported */
251 }
252
253
254 /*
255 * Locating a page hash
256 */
257 static const unsigned char *
hashes(const CS_CodeDirectory * cd,uint32_t page,size_t hash_len,const char * lower_bound,const char * upper_bound)258 hashes(
259 const CS_CodeDirectory *cd,
260 uint32_t page,
261 size_t hash_len,
262 const char *lower_bound,
263 const char *upper_bound)
264 {
265 const unsigned char *base, *top, *hash;
266 uint32_t nCodeSlots = ntohl(cd->nCodeSlots);
267
268 assert(cs_valid_range(cd, cd + 1, lower_bound, upper_bound));
269
270 if ((ntohl(cd->version) >= CS_SUPPORTSSCATTER) && (ntohl(cd->scatterOffset))) {
271 /* Get first scatter struct */
272 const SC_Scatter *scatter = (const SC_Scatter*)
273 ((const char*)cd + ntohl(cd->scatterOffset));
274 uint32_t hashindex = 0, scount, sbase = 0;
275 /* iterate all scatter structs */
276 do {
277 if ((const char*)scatter > (const char*)cd + ntohl(cd->length)) {
278 if (cs_debug) {
279 printf("CODE SIGNING: Scatter extends past Code Directory\n");
280 }
281 return NULL;
282 }
283
284 scount = ntohl(scatter->count);
285 uint32_t new_base = ntohl(scatter->base);
286
287 /* last scatter? */
288 if (scount == 0) {
289 return NULL;
290 }
291
292 if ((hashindex > 0) && (new_base <= sbase)) {
293 if (cs_debug) {
294 printf("CODE SIGNING: unordered Scatter, prev base %d, cur base %d\n",
295 sbase, new_base);
296 }
297 return NULL; /* unordered scatter array */
298 }
299 sbase = new_base;
300
301 /* this scatter beyond page we're looking for? */
302 if (sbase > page) {
303 return NULL;
304 }
305
306 if (sbase + scount >= page) {
307 /* Found the scatter struct that is
308 * referencing our page */
309
310 /* base = address of first hash covered by scatter */
311 base = (const unsigned char *)cd + ntohl(cd->hashOffset) +
312 hashindex * hash_len;
313 /* top = address of first hash after this scatter */
314 top = base + scount * hash_len;
315 if (!cs_valid_range(base, top, lower_bound,
316 upper_bound) ||
317 hashindex > nCodeSlots) {
318 return NULL;
319 }
320
321 break;
322 }
323
324 /* this scatter struct is before the page we're looking
325 * for. Iterate. */
326 hashindex += scount;
327 scatter++;
328 } while (1);
329
330 hash = base + (page - sbase) * hash_len;
331 } else {
332 base = (const unsigned char *)cd + ntohl(cd->hashOffset);
333 top = base + nCodeSlots * hash_len;
334 if (!cs_valid_range(base, top, lower_bound, upper_bound) ||
335 page > nCodeSlots) {
336 return NULL;
337 }
338 assert(page < nCodeSlots);
339
340 hash = base + page * hash_len;
341 }
342
343 if (!cs_valid_range(hash, hash + hash_len,
344 lower_bound, upper_bound)) {
345 hash = NULL;
346 }
347
348 return hash;
349 }
350
351 /*
352 * cs_validate_codedirectory
353 *
354 * Validate that pointers inside the code directory to make sure that
355 * all offsets and lengths are constrained within the buffer.
356 *
357 * Parameters: cd Pointer to code directory buffer
358 * length Length of buffer
359 *
360 * Returns: 0 Success
361 * EBADEXEC Invalid code signature
362 */
363
364 static int
cs_validate_codedirectory(const CS_CodeDirectory * cd,size_t length)365 cs_validate_codedirectory(const CS_CodeDirectory *cd, size_t length)
366 {
367 struct cs_hash const *hashtype;
368
369 if (length < sizeof(*cd)) {
370 return EBADEXEC;
371 }
372 if (ntohl(cd->magic) != CSMAGIC_CODEDIRECTORY) {
373 return EBADEXEC;
374 }
375 if (cd->pageSize < PAGE_SHIFT_4K || cd->pageSize > PAGE_SHIFT) {
376 return EBADEXEC;
377 }
378 hashtype = cs_find_md(cd->hashType);
379 if (hashtype == NULL) {
380 return EBADEXEC;
381 }
382
383 if (cd->hashSize != hashtype->cs_size) {
384 return EBADEXEC;
385 }
386
387 if (length < ntohl(cd->hashOffset)) {
388 return EBADEXEC;
389 }
390
391 /* check that nSpecialSlots fits in the buffer in front of hashOffset */
392 if (ntohl(cd->hashOffset) / hashtype->cs_size < ntohl(cd->nSpecialSlots)) {
393 return EBADEXEC;
394 }
395
396 /* check that codeslots fits in the buffer */
397 if ((length - ntohl(cd->hashOffset)) / hashtype->cs_size < ntohl(cd->nCodeSlots)) {
398 return EBADEXEC;
399 }
400
401 if (ntohl(cd->version) >= CS_SUPPORTSSCATTER && cd->scatterOffset) {
402 if (length < ntohl(cd->scatterOffset)) {
403 return EBADEXEC;
404 }
405
406 const SC_Scatter *scatter = (const SC_Scatter *)
407 (((const uint8_t *)cd) + ntohl(cd->scatterOffset));
408 uint32_t nPages = 0;
409
410 /*
411 * Check each scatter buffer, since we don't know the
412 * length of the scatter buffer array, we have to
413 * check each entry.
414 */
415 while (1) {
416 /* check that the end of each scatter buffer in within the length */
417 if (((const uint8_t *)scatter) + sizeof(scatter[0]) > (const uint8_t *)cd + length) {
418 return EBADEXEC;
419 }
420 uint32_t scount = ntohl(scatter->count);
421 if (scount == 0) {
422 break;
423 }
424 if (nPages + scount < nPages) {
425 return EBADEXEC;
426 }
427 nPages += scount;
428 scatter++;
429
430 /* XXX check that basees doesn't overlap */
431 /* XXX check that targetOffset doesn't overlap */
432 }
433 #if 0 /* rdar://12579439 */
434 if (nPages != ntohl(cd->nCodeSlots)) {
435 return EBADEXEC;
436 }
437 #endif
438 }
439
440 if (length < ntohl(cd->identOffset)) {
441 return EBADEXEC;
442 }
443
444 /* identifier is NUL terminated string */
445 if (cd->identOffset) {
446 const uint8_t *ptr = (const uint8_t *)cd + ntohl(cd->identOffset);
447 if (memchr(ptr, 0, length - ntohl(cd->identOffset)) == NULL) {
448 return EBADEXEC;
449 }
450 }
451
452 /* team identifier is NULL terminated string */
453 if (ntohl(cd->version) >= CS_SUPPORTSTEAMID && ntohl(cd->teamOffset)) {
454 if (length < ntohl(cd->teamOffset)) {
455 return EBADEXEC;
456 }
457
458 const uint8_t *ptr = (const uint8_t *)cd + ntohl(cd->teamOffset);
459 if (memchr(ptr, 0, length - ntohl(cd->teamOffset)) == NULL) {
460 return EBADEXEC;
461 }
462 }
463
464 /* linkage is variable length binary data */
465 if (ntohl(cd->version) >= CS_SUPPORTSLINKAGE && cd->linkageHashType != 0) {
466 const uintptr_t ptr = (uintptr_t)cd + ntohl(cd->linkageOffset);
467 const uintptr_t ptr_end = ptr + ntohl(cd->linkageSize);
468
469 if (ptr_end < ptr || ptr < (uintptr_t)cd || ptr_end > (uintptr_t)cd + length) {
470 return EBADEXEC;
471 }
472 }
473
474
475 return 0;
476 }
477
478 /*
479 *
480 */
481
482 static int
cs_validate_blob(const CS_GenericBlob * blob,size_t length)483 cs_validate_blob(const CS_GenericBlob *blob, size_t length)
484 {
485 if (length < sizeof(CS_GenericBlob) || length < ntohl(blob->length)) {
486 return EBADEXEC;
487 }
488 return 0;
489 }
490
491 /*
492 * cs_validate_csblob
493 *
494 * Validate that superblob/embedded code directory to make sure that
495 * all internal pointers are valid.
496 *
497 * Will validate both a superblob csblob and a "raw" code directory.
498 *
499 *
500 * Parameters: buffer Pointer to code signature
501 * length Length of buffer
502 * rcd returns pointer to code directory
503 *
504 * Returns: 0 Success
505 * EBADEXEC Invalid code signature
506 */
507
508 static int
cs_validate_csblob(const uint8_t * addr,const size_t blob_size,const CS_CodeDirectory ** rcd,const CS_GenericBlob ** rentitlements,const CS_GenericBlob ** rder_entitlements)509 cs_validate_csblob(
510 const uint8_t *addr,
511 const size_t blob_size,
512 const CS_CodeDirectory **rcd,
513 const CS_GenericBlob **rentitlements,
514 const CS_GenericBlob **rder_entitlements)
515 {
516 const CS_GenericBlob *blob;
517 int error;
518 size_t length;
519
520 *rcd = NULL;
521 *rentitlements = NULL;
522 *rder_entitlements = NULL;
523
524 blob = (const CS_GenericBlob *)(const void *)addr;
525
526 length = blob_size;
527 error = cs_validate_blob(blob, length);
528 if (error) {
529 return error;
530 }
531 length = ntohl(blob->length);
532
533 if (ntohl(blob->magic) == CSMAGIC_EMBEDDED_SIGNATURE) {
534 const CS_SuperBlob *sb;
535 uint32_t n, count;
536 const CS_CodeDirectory *best_cd = NULL;
537 unsigned int best_rank = 0;
538 #if PLATFORM_WatchOS
539 const CS_CodeDirectory *sha1_cd = NULL;
540 #endif
541
542 if (length < sizeof(CS_SuperBlob)) {
543 return EBADEXEC;
544 }
545
546 sb = (const CS_SuperBlob *)blob;
547 count = ntohl(sb->count);
548
549 /* check that the array of BlobIndex fits in the rest of the data */
550 if ((length - sizeof(CS_SuperBlob)) / sizeof(CS_BlobIndex) < count) {
551 return EBADEXEC;
552 }
553
554 /* now check each BlobIndex */
555 for (n = 0; n < count; n++) {
556 const CS_BlobIndex *blobIndex = &sb->index[n];
557 uint32_t type = ntohl(blobIndex->type);
558 uint32_t offset = ntohl(blobIndex->offset);
559 if (length < offset) {
560 return EBADEXEC;
561 }
562
563 const CS_GenericBlob *subBlob =
564 (const CS_GenericBlob *)(const void *)(addr + offset);
565
566 size_t subLength = length - offset;
567
568 if ((error = cs_validate_blob(subBlob, subLength)) != 0) {
569 return error;
570 }
571 subLength = ntohl(subBlob->length);
572
573 /* extra validation for CDs, that is also returned */
574 if (type == CSSLOT_CODEDIRECTORY || (type >= CSSLOT_ALTERNATE_CODEDIRECTORIES && type < CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT)) {
575 const CS_CodeDirectory *candidate = (const CS_CodeDirectory *)subBlob;
576 if ((error = cs_validate_codedirectory(candidate, subLength)) != 0) {
577 return error;
578 }
579 unsigned int rank = hash_rank(candidate);
580 if (cs_debug > 3) {
581 printf("CodeDirectory type %d rank %d at slot 0x%x index %d\n", candidate->hashType, (int)rank, (int)type, (int)n);
582 }
583 if (best_cd == NULL || rank > best_rank) {
584 best_cd = candidate;
585 best_rank = rank;
586
587 if (cs_debug > 2) {
588 printf("using CodeDirectory type %d (rank %d)\n", (int)best_cd->hashType, best_rank);
589 }
590 *rcd = best_cd;
591 } else if (best_cd != NULL && rank == best_rank) {
592 /* repeat of a hash type (1:1 mapped to ranks), illegal and suspicious */
593 printf("multiple hash=%d CodeDirectories in signature; rejecting\n", best_cd->hashType);
594 return EBADEXEC;
595 }
596 #if PLATFORM_WatchOS
597 if (candidate->hashType == CS_HASHTYPE_SHA1) {
598 if (sha1_cd != NULL) {
599 printf("multiple sha1 CodeDirectories in signature; rejecting\n");
600 return EBADEXEC;
601 }
602 sha1_cd = candidate;
603 }
604 #endif
605 } else if (type == CSSLOT_ENTITLEMENTS) {
606 if (ntohl(subBlob->magic) != CSMAGIC_EMBEDDED_ENTITLEMENTS) {
607 return EBADEXEC;
608 }
609 if (*rentitlements != NULL) {
610 printf("multiple entitlements blobs\n");
611 return EBADEXEC;
612 }
613 *rentitlements = subBlob;
614 } else if (type == CSSLOT_DER_ENTITLEMENTS) {
615 if (ntohl(subBlob->magic) != CSMAGIC_EMBEDDED_DER_ENTITLEMENTS) {
616 return EBADEXEC;
617 }
618 if (*rder_entitlements != NULL) {
619 printf("multiple der entitlements blobs\n");
620 return EBADEXEC;
621 }
622 *rder_entitlements = subBlob;
623 }
624 }
625
626 #if PLATFORM_WatchOS
627 /* To keep watchOS fast enough, we have to resort to sha1 for
628 * some code.
629 *
630 * At the time of writing this comment, known sha1 attacks are
631 * collision attacks (not preimage or second preimage
632 * attacks), which do not apply to platform binaries since
633 * they have a fixed hash in the trust cache. Given this
634 * property, we only prefer sha1 code directories for adhoc
635 * signatures, which always have to be in a trust cache to be
636 * valid (can-load-cdhash does not exist for watchOS). Those
637 * are, incidentally, also the platform binaries, for which we
638 * care about the performance hit that sha256 would bring us.
639 *
640 * Platform binaries may still contain a (not chosen) sha256
641 * code directory, which keeps software updates that switch to
642 * sha256-only small.
643 */
644
645 if (*rcd != NULL && sha1_cd != NULL && (ntohl(sha1_cd->flags) & CS_ADHOC)) {
646 if (sha1_cd->flags != (*rcd)->flags) {
647 printf("mismatched flags between hash %d (flags: %#x) and sha1 (flags: %#x) cd.\n",
648 (int)(*rcd)->hashType, (*rcd)->flags, sha1_cd->flags);
649 *rcd = NULL;
650 return EBADEXEC;
651 }
652
653 *rcd = sha1_cd;
654 }
655 #endif
656 } else if (ntohl(blob->magic) == CSMAGIC_CODEDIRECTORY) {
657 if ((error = cs_validate_codedirectory((const CS_CodeDirectory *)(const void *)addr, length)) != 0) {
658 return error;
659 }
660 *rcd = (const CS_CodeDirectory *)blob;
661 } else {
662 return EBADEXEC;
663 }
664
665 if (*rcd == NULL) {
666 return EBADEXEC;
667 }
668
669 return 0;
670 }
671
672 /*
673 * cs_find_blob_bytes
674 *
675 * Find an blob from the superblob/code directory. The blob must have
676 * been been validated by cs_validate_csblob() before calling
677 * this. Use csblob_find_blob() instead.
678 *
679 * Will also find a "raw" code directory if its stored as well as
680 * searching the superblob.
681 *
682 * Parameters: buffer Pointer to code signature
683 * length Length of buffer
684 * type type of blob to find
685 * magic the magic number for that blob
686 *
687 * Returns: pointer Success
688 * NULL Buffer not found
689 */
690
691 const CS_GenericBlob *
csblob_find_blob_bytes(const uint8_t * addr,size_t length,uint32_t type,uint32_t magic)692 csblob_find_blob_bytes(const uint8_t *addr, size_t length, uint32_t type, uint32_t magic)
693 {
694 const CS_GenericBlob *blob = (const CS_GenericBlob *)(const void *)addr;
695
696 if ((addr + length) < addr) {
697 panic("CODE SIGNING: CS Blob length overflow for addr: %p", addr);
698 }
699
700 if (ntohl(blob->magic) == CSMAGIC_EMBEDDED_SIGNATURE) {
701 const CS_SuperBlob *sb = (const CS_SuperBlob *)blob;
702 size_t n, count = ntohl(sb->count);
703
704 for (n = 0; n < count; n++) {
705 if (ntohl(sb->index[n].type) != type) {
706 continue;
707 }
708 uint32_t offset = ntohl(sb->index[n].offset);
709 if (length - sizeof(const CS_GenericBlob) < offset) {
710 return NULL;
711 }
712 blob = (const CS_GenericBlob *)(const void *)(addr + offset);
713 if (ntohl(blob->magic) != magic) {
714 continue;
715 }
716 if (((vm_address_t)blob + ntohl(blob->length)) < (vm_address_t)blob) {
717 panic("CODE SIGNING: CS Blob length overflow for blob at: %p", blob);
718 } else if (((vm_address_t)blob + ntohl(blob->length)) > (vm_address_t)(addr + length)) {
719 continue;
720 }
721 return blob;
722 }
723 } else if (type == CSSLOT_CODEDIRECTORY && ntohl(blob->magic) == CSMAGIC_CODEDIRECTORY
724 && magic == CSMAGIC_CODEDIRECTORY) {
725 if (((vm_address_t)blob + ntohl(blob->length)) < (vm_address_t)blob) {
726 panic("CODE SIGNING: CS Blob length overflow for code directory blob at: %p", blob);
727 } else if (((vm_address_t)blob + ntohl(blob->length)) > (vm_address_t)(addr + length)) {
728 return NULL;
729 }
730 return blob;
731 }
732 return NULL;
733 }
734
735
736 const CS_GenericBlob *
csblob_find_blob(struct cs_blob * csblob,uint32_t type,uint32_t magic)737 csblob_find_blob(struct cs_blob *csblob, uint32_t type, uint32_t magic)
738 {
739 if ((csblob->csb_flags & CS_VALID) == 0) {
740 return NULL;
741 }
742 return csblob_find_blob_bytes((const uint8_t *)csblob->csb_mem_kaddr, csblob->csb_mem_size, type, magic);
743 }
744
745 static const uint8_t *
find_special_slot(const CS_CodeDirectory * cd,size_t slotsize,uint32_t slot)746 find_special_slot(const CS_CodeDirectory *cd, size_t slotsize, uint32_t slot)
747 {
748 /* there is no zero special slot since that is the first code slot */
749 if (ntohl(cd->nSpecialSlots) < slot || slot == 0) {
750 return NULL;
751 }
752
753 return (const uint8_t *)cd + ntohl(cd->hashOffset) - (slotsize * slot);
754 }
755
756 static uint8_t cshash_zero[CS_HASH_MAX_SIZE] = { 0 };
757
758 int
csblob_get_entitlements(struct cs_blob * csblob,void ** out_start,size_t * out_length)759 csblob_get_entitlements(struct cs_blob *csblob, void **out_start, size_t *out_length)
760 {
761 uint8_t computed_hash[CS_HASH_MAX_SIZE];
762 const CS_GenericBlob *entitlements;
763 const CS_CodeDirectory *code_dir;
764 const uint8_t *embedded_hash;
765 union cs_hash_union context;
766
767 *out_start = NULL;
768 *out_length = 0;
769
770 if (csblob->csb_hashtype == NULL || csblob->csb_hashtype->cs_digest_size > sizeof(computed_hash)) {
771 return EBADEXEC;
772 }
773
774 code_dir = csblob->csb_cd;
775
776 if ((csblob->csb_flags & CS_VALID) == 0) {
777 entitlements = NULL;
778 } else {
779 entitlements = csblob->csb_entitlements_blob;
780 }
781 embedded_hash = find_special_slot(code_dir, csblob->csb_hashtype->cs_size, CSSLOT_ENTITLEMENTS);
782
783 if (embedded_hash == NULL) {
784 if (entitlements) {
785 return EBADEXEC;
786 }
787 return 0;
788 } else if (entitlements == NULL) {
789 if (memcmp(embedded_hash, cshash_zero, csblob->csb_hashtype->cs_size) != 0) {
790 return EBADEXEC;
791 } else {
792 return 0;
793 }
794 }
795
796 csblob->csb_hashtype->cs_init(&context);
797 csblob->csb_hashtype->cs_update(&context, entitlements, ntohl(entitlements->length));
798 csblob->csb_hashtype->cs_final(computed_hash, &context);
799
800 if (memcmp(computed_hash, embedded_hash, csblob->csb_hashtype->cs_size) != 0) {
801 return EBADEXEC;
802 }
803
804 *out_start = __DECONST(void *, entitlements);
805 *out_length = ntohl(entitlements->length);
806
807 return 0;
808 }
809
810 int
csblob_get_der_entitlements(struct cs_blob * csblob,const CS_GenericBlob ** out_start,size_t * out_length)811 csblob_get_der_entitlements(struct cs_blob *csblob, const CS_GenericBlob **out_start, size_t *out_length)
812 {
813 uint8_t computed_hash[CS_HASH_MAX_SIZE];
814 const CS_GenericBlob *der_entitlements;
815 const CS_CodeDirectory *code_dir;
816 const uint8_t *embedded_hash;
817 union cs_hash_union context;
818
819 *out_start = NULL;
820 *out_length = 0;
821
822 if (csblob->csb_hashtype == NULL || csblob->csb_hashtype->cs_digest_size > sizeof(computed_hash)) {
823 return EBADEXEC;
824 }
825
826 code_dir = csblob->csb_cd;
827
828 if ((csblob->csb_flags & CS_VALID) == 0) {
829 der_entitlements = NULL;
830 } else {
831 der_entitlements = csblob->csb_der_entitlements_blob;
832 }
833 embedded_hash = find_special_slot(code_dir, csblob->csb_hashtype->cs_size, CSSLOT_DER_ENTITLEMENTS);
834
835 if (embedded_hash == NULL) {
836 if (der_entitlements) {
837 return EBADEXEC;
838 }
839 return 0;
840 } else if (der_entitlements == NULL) {
841 if (memcmp(embedded_hash, cshash_zero, csblob->csb_hashtype->cs_size) != 0) {
842 return EBADEXEC;
843 } else {
844 return 0;
845 }
846 }
847
848 csblob->csb_hashtype->cs_init(&context);
849 csblob->csb_hashtype->cs_update(&context, der_entitlements, ntohl(der_entitlements->length));
850 csblob->csb_hashtype->cs_final(computed_hash, &context);
851
852 if (memcmp(computed_hash, embedded_hash, csblob->csb_hashtype->cs_size) != 0) {
853 return EBADEXEC;
854 }
855
856 *out_start = der_entitlements;
857 *out_length = ntohl(der_entitlements->length);
858
859 return 0;
860 }
861
862 /*
863 * Register a provisioning profile with a cs_blob.
864 */
865 int
csblob_register_profile(struct cs_blob __unused * csblob,void __unused * profile_addr,vm_size_t __unused profile_size)866 csblob_register_profile(struct cs_blob __unused *csblob, void __unused *profile_addr, vm_size_t __unused profile_size)
867 {
868 return 0;
869 }
870
871 /*
872 * CODESIGNING
873 * End of routines to navigate code signing data structures in the kernel.
874 */
875
876
877
878 /*
879 * ubc_info_init
880 *
881 * Allocate and attach an empty ubc_info structure to a vnode
882 *
883 * Parameters: vp Pointer to the vnode
884 *
885 * Returns: 0 Success
886 * vnode_size:ENOMEM Not enough space
887 * vnode_size:??? Other error from vnode_getattr
888 *
889 */
890 int
ubc_info_init(struct vnode * vp)891 ubc_info_init(struct vnode *vp)
892 {
893 return ubc_info_init_internal(vp, 0, 0);
894 }
895
896
897 /*
898 * ubc_info_init_withsize
899 *
900 * Allocate and attach a sized ubc_info structure to a vnode
901 *
902 * Parameters: vp Pointer to the vnode
903 * filesize The size of the file
904 *
905 * Returns: 0 Success
906 * vnode_size:ENOMEM Not enough space
907 * vnode_size:??? Other error from vnode_getattr
908 */
909 int
ubc_info_init_withsize(struct vnode * vp,off_t filesize)910 ubc_info_init_withsize(struct vnode *vp, off_t filesize)
911 {
912 return ubc_info_init_internal(vp, 1, filesize);
913 }
914
915
916 /*
917 * ubc_info_init_internal
918 *
919 * Allocate and attach a ubc_info structure to a vnode
920 *
921 * Parameters: vp Pointer to the vnode
922 * withfsize{0,1} Zero if the size should be obtained
923 * from the vnode; otherwise, use filesize
924 * filesize The size of the file, if withfsize == 1
925 *
926 * Returns: 0 Success
927 * vnode_size:ENOMEM Not enough space
928 * vnode_size:??? Other error from vnode_getattr
929 *
930 * Notes: We call a blocking zalloc(), and the zone was created as an
931 * expandable and collectable zone, so if no memory is available,
932 * it is possible for zalloc() to block indefinitely. zalloc()
933 * may also panic if the zone of zones is exhausted, since it's
934 * NOT expandable.
935 *
936 * We unconditionally call vnode_pager_setup(), even if this is
937 * a reuse of a ubc_info; in that case, we should probably assert
938 * that it does not already have a pager association, but do not.
939 *
940 * Since memory_object_create_named() can only fail from receiving
941 * an invalid pager argument, the explicit check and panic is
942 * merely precautionary.
943 */
944 static int
ubc_info_init_internal(vnode_t vp,int withfsize,off_t filesize)945 ubc_info_init_internal(vnode_t vp, int withfsize, off_t filesize)
946 {
947 struct ubc_info *uip;
948 void * pager;
949 int error = 0;
950 kern_return_t kret;
951 memory_object_control_t control;
952
953 uip = vp->v_ubcinfo;
954
955 /*
956 * If there is not already a ubc_info attached to the vnode, we
957 * attach one; otherwise, we will reuse the one that's there.
958 */
959 if (uip == UBC_INFO_NULL) {
960 uip = zalloc_flags(ubc_info_zone, Z_WAITOK | Z_ZERO);
961
962 uip->ui_vnode = vp;
963 uip->ui_flags = UI_INITED;
964 uip->ui_ucred = NOCRED;
965 }
966 assert(uip->ui_flags != UI_NONE);
967 assert(uip->ui_vnode == vp);
968
969 /* now set this ubc_info in the vnode */
970 vp->v_ubcinfo = uip;
971
972 /*
973 * Allocate a pager object for this vnode
974 *
975 * XXX The value of the pager parameter is currently ignored.
976 * XXX Presumably, this API changed to avoid the race between
977 * XXX setting the pager and the UI_HASPAGER flag.
978 */
979 pager = (void *)vnode_pager_setup(vp, uip->ui_pager);
980 assert(pager);
981
982 /*
983 * Explicitly set the pager into the ubc_info, after setting the
984 * UI_HASPAGER flag.
985 */
986 SET(uip->ui_flags, UI_HASPAGER);
987 uip->ui_pager = pager;
988
989 /*
990 * Note: We can not use VNOP_GETATTR() to get accurate
991 * value of ui_size because this may be an NFS vnode, and
992 * nfs_getattr() can call vinvalbuf(); if this happens,
993 * ubc_info is not set up to deal with that event.
994 * So use bogus size.
995 */
996
997 /*
998 * create a vnode - vm_object association
999 * memory_object_create_named() creates a "named" reference on the
1000 * memory object we hold this reference as long as the vnode is
1001 * "alive." Since memory_object_create_named() took its own reference
1002 * on the vnode pager we passed it, we can drop the reference
1003 * vnode_pager_setup() returned here.
1004 */
1005 kret = memory_object_create_named(pager,
1006 (memory_object_size_t)uip->ui_size, &control);
1007 vnode_pager_deallocate(pager);
1008 if (kret != KERN_SUCCESS) {
1009 panic("ubc_info_init: memory_object_create_named returned %d", kret);
1010 }
1011
1012 assert(control);
1013 uip->ui_control = control; /* cache the value of the mo control */
1014 SET(uip->ui_flags, UI_HASOBJREF); /* with a named reference */
1015
1016 if (withfsize == 0) {
1017 /* initialize the size */
1018 error = vnode_size(vp, &uip->ui_size, vfs_context_current());
1019 if (error) {
1020 uip->ui_size = 0;
1021 }
1022 } else {
1023 uip->ui_size = filesize;
1024 }
1025 vp->v_lflag |= VNAMED_UBC; /* vnode has a named ubc reference */
1026
1027 return error;
1028 }
1029
1030
1031 /*
1032 * ubc_info_free
1033 *
1034 * Free a ubc_info structure
1035 *
1036 * Parameters: uip A pointer to the ubc_info to free
1037 *
1038 * Returns: (void)
1039 *
1040 * Notes: If there is a credential that has subsequently been associated
1041 * with the ubc_info via a call to ubc_setcred(), the reference
1042 * to the credential is dropped.
1043 *
1044 * It's actually impossible for a ubc_info.ui_control to take the
1045 * value MEMORY_OBJECT_CONTROL_NULL.
1046 */
1047 static void
ubc_info_free(struct ubc_info * uip)1048 ubc_info_free(struct ubc_info *uip)
1049 {
1050 if (IS_VALID_CRED(uip->ui_ucred)) {
1051 kauth_cred_unref(&uip->ui_ucred);
1052 }
1053
1054 if (uip->ui_control != MEMORY_OBJECT_CONTROL_NULL) {
1055 memory_object_control_deallocate(uip->ui_control);
1056 }
1057
1058 cluster_release(uip);
1059 ubc_cs_free(uip);
1060
1061 zfree(ubc_info_zone, uip);
1062 return;
1063 }
1064
1065
1066 void
ubc_info_deallocate(struct ubc_info * uip)1067 ubc_info_deallocate(struct ubc_info *uip)
1068 {
1069 ubc_info_free(uip);
1070 }
1071
1072 /*
1073 * ubc_setsize_ex
1074 *
1075 * Tell the VM that the the size of the file represented by the vnode has
1076 * changed
1077 *
1078 * Parameters: vp The vp whose backing file size is
1079 * being changed
1080 * nsize The new size of the backing file
1081 * opts Options
1082 *
1083 * Returns: EINVAL for new size < 0
1084 * ENOENT if no UBC info exists
1085 * EAGAIN if UBC_SETSIZE_NO_FS_REENTRY option is set and new_size < old size
1086 * Other errors (mapped to errno_t) returned by VM functions
1087 *
1088 * Notes: This function will indicate success if the new size is the
1089 * same or larger than the old size (in this case, the
1090 * remainder of the file will require modification or use of
1091 * an existing upl to access successfully).
1092 *
1093 * This function will fail if the new file size is smaller,
1094 * and the memory region being invalidated was unable to
1095 * actually be invalidated and/or the last page could not be
1096 * flushed, if the new size is not aligned to a page
1097 * boundary. This is usually indicative of an I/O error.
1098 */
1099 errno_t
ubc_setsize_ex(struct vnode * vp,off_t nsize,ubc_setsize_opts_t opts)1100 ubc_setsize_ex(struct vnode *vp, off_t nsize, ubc_setsize_opts_t opts)
1101 {
1102 off_t osize; /* ui_size before change */
1103 off_t lastpg, olastpgend, lastoff;
1104 struct ubc_info *uip;
1105 memory_object_control_t control;
1106 kern_return_t kret = KERN_SUCCESS;
1107
1108 if (nsize < (off_t)0) {
1109 return EINVAL;
1110 }
1111
1112 if (!UBCINFOEXISTS(vp)) {
1113 return ENOENT;
1114 }
1115
1116 uip = vp->v_ubcinfo;
1117 osize = uip->ui_size;
1118
1119 if (ISSET(opts, UBC_SETSIZE_NO_FS_REENTRY) && nsize < osize) {
1120 return EAGAIN;
1121 }
1122
1123 /*
1124 * Update the size before flushing the VM
1125 */
1126 uip->ui_size = nsize;
1127
1128 if (nsize >= osize) { /* Nothing more to do */
1129 if (nsize > osize) {
1130 lock_vnode_and_post(vp, NOTE_EXTEND);
1131 }
1132
1133 return 0;
1134 }
1135
1136 /*
1137 * When the file shrinks, invalidate the pages beyond the
1138 * new size. Also get rid of garbage beyond nsize on the
1139 * last page. The ui_size already has the nsize, so any
1140 * subsequent page-in will zero-fill the tail properly
1141 */
1142 lastpg = trunc_page_64(nsize);
1143 olastpgend = round_page_64(osize);
1144 control = uip->ui_control;
1145 assert(control);
1146 lastoff = (nsize & PAGE_MASK_64);
1147
1148 if (lastoff) {
1149 upl_t upl;
1150 upl_page_info_t *pl;
1151
1152 /*
1153 * new EOF ends up in the middle of a page
1154 * zero the tail of this page if it's currently
1155 * present in the cache
1156 */
1157 kret = ubc_create_upl_kernel(vp, lastpg, PAGE_SIZE, &upl, &pl, UPL_SET_LITE | UPL_WILL_MODIFY, VM_KERN_MEMORY_FILE);
1158
1159 if (kret != KERN_SUCCESS) {
1160 panic("ubc_setsize: ubc_create_upl (error = %d)", kret);
1161 }
1162
1163 if (upl_valid_page(pl, 0)) {
1164 cluster_zero(upl, (uint32_t)lastoff, PAGE_SIZE - (uint32_t)lastoff, NULL);
1165 }
1166
1167 ubc_upl_abort_range(upl, 0, PAGE_SIZE, UPL_ABORT_FREE_ON_EMPTY);
1168
1169 lastpg += PAGE_SIZE_64;
1170 }
1171 if (olastpgend > lastpg) {
1172 int flags;
1173
1174 if (lastpg == 0) {
1175 flags = MEMORY_OBJECT_DATA_FLUSH_ALL;
1176 } else {
1177 flags = MEMORY_OBJECT_DATA_FLUSH;
1178 }
1179 /*
1180 * invalidate the pages beyond the new EOF page
1181 *
1182 */
1183 kret = memory_object_lock_request(control,
1184 (memory_object_offset_t)lastpg,
1185 (memory_object_size_t)(olastpgend - lastpg), NULL, NULL,
1186 MEMORY_OBJECT_RETURN_NONE, flags, VM_PROT_NO_CHANGE);
1187 if (kret != KERN_SUCCESS) {
1188 printf("ubc_setsize: invalidate failed (error = %d)\n", kret);
1189 }
1190 }
1191 return mach_to_bsd_errno(kret);
1192 }
1193
1194 // Returns true for success
1195 int
ubc_setsize(vnode_t vp,off_t nsize)1196 ubc_setsize(vnode_t vp, off_t nsize)
1197 {
1198 return ubc_setsize_ex(vp, nsize, 0) == 0;
1199 }
1200
1201 /*
1202 * ubc_getsize
1203 *
1204 * Get the size of the file assocated with the specified vnode
1205 *
1206 * Parameters: vp The vnode whose size is of interest
1207 *
1208 * Returns: 0 There is no ubc_info associated with
1209 * this vnode, or the size is zero
1210 * !0 The size of the file
1211 *
1212 * Notes: Using this routine, it is not possible for a caller to
1213 * successfully distinguish between a vnode associate with a zero
1214 * length file, and a vnode with no associated ubc_info. The
1215 * caller therefore needs to not care, or needs to ensure that
1216 * they have previously successfully called ubc_info_init() or
1217 * ubc_info_init_withsize().
1218 */
1219 off_t
ubc_getsize(struct vnode * vp)1220 ubc_getsize(struct vnode *vp)
1221 {
1222 /* people depend on the side effect of this working this way
1223 * as they call this for directory
1224 */
1225 if (!UBCINFOEXISTS(vp)) {
1226 return (off_t)0;
1227 }
1228 return vp->v_ubcinfo->ui_size;
1229 }
1230
1231
1232 /*
1233 * ubc_umount
1234 *
1235 * Call ubc_msync(vp, 0, EOF, NULL, UBC_PUSHALL) on all the vnodes for this
1236 * mount point
1237 *
1238 * Parameters: mp The mount point
1239 *
1240 * Returns: 0 Success
1241 *
1242 * Notes: There is no failure indication for this function.
1243 *
1244 * This function is used in the unmount path; since it may block
1245 * I/O indefinitely, it should not be used in the forced unmount
1246 * path, since a device unavailability could also block that
1247 * indefinitely.
1248 *
1249 * Because there is no device ejection interlock on USB, FireWire,
1250 * or similar devices, it's possible that an ejection that begins
1251 * subsequent to the vnode_iterate() completing, either on one of
1252 * those devices, or a network mount for which the server quits
1253 * responding, etc., may cause the caller to block indefinitely.
1254 */
1255 __private_extern__ int
ubc_umount(struct mount * mp)1256 ubc_umount(struct mount *mp)
1257 {
1258 vnode_iterate(mp, 0, ubc_umcallback, 0);
1259 return 0;
1260 }
1261
1262
1263 /*
1264 * ubc_umcallback
1265 *
1266 * Used by ubc_umount() as an internal implementation detail; see ubc_umount()
1267 * and vnode_iterate() for details of implementation.
1268 */
1269 static int
ubc_umcallback(vnode_t vp,__unused void * args)1270 ubc_umcallback(vnode_t vp, __unused void * args)
1271 {
1272 if (UBCINFOEXISTS(vp)) {
1273 (void) ubc_msync(vp, (off_t)0, ubc_getsize(vp), NULL, UBC_PUSHALL);
1274 }
1275 return VNODE_RETURNED;
1276 }
1277
1278
1279 /*
1280 * ubc_getcred
1281 *
1282 * Get the credentials currently active for the ubc_info associated with the
1283 * vnode.
1284 *
1285 * Parameters: vp The vnode whose ubc_info credentials
1286 * are to be retrieved
1287 *
1288 * Returns: !NOCRED The credentials
1289 * NOCRED If there is no ubc_info for the vnode,
1290 * or if there is one, but it has not had
1291 * any credentials associated with it via
1292 * a call to ubc_setcred()
1293 */
1294 kauth_cred_t
ubc_getcred(struct vnode * vp)1295 ubc_getcred(struct vnode *vp)
1296 {
1297 if (UBCINFOEXISTS(vp)) {
1298 return vp->v_ubcinfo->ui_ucred;
1299 }
1300
1301 return NOCRED;
1302 }
1303
1304
1305 /*
1306 * ubc_setthreadcred
1307 *
1308 * If they are not already set, set the credentials of the ubc_info structure
1309 * associated with the vnode to those of the supplied thread; otherwise leave
1310 * them alone.
1311 *
1312 * Parameters: vp The vnode whose ubc_info creds are to
1313 * be set
1314 * p The process whose credentials are to
1315 * be used, if not running on an assumed
1316 * credential
1317 * thread The thread whose credentials are to
1318 * be used
1319 *
1320 * Returns: 1 This vnode has no associated ubc_info
1321 * 0 Success
1322 *
1323 * Notes: This function takes a proc parameter to account for bootstrap
1324 * issues where a task or thread may call this routine, either
1325 * before credentials have been initialized by bsd_init(), or if
1326 * there is no BSD info asscoiate with a mach thread yet. This
1327 * is known to happen in both the initial swap and memory mapping
1328 * calls.
1329 *
1330 * This function is generally used only in the following cases:
1331 *
1332 * o a memory mapped file via the mmap() system call
1333 * o a swap store backing file
1334 * o subsequent to a successful write via vn_write()
1335 *
1336 * The information is then used by the NFS client in order to
1337 * cons up a wire message in either the page-in or page-out path.
1338 *
1339 * There are two potential problems with the use of this API:
1340 *
1341 * o Because the write path only set it on a successful
1342 * write, there is a race window between setting the
1343 * credential and its use to evict the pages to the
1344 * remote file server
1345 *
1346 * o Because a page-in may occur prior to a write, the
1347 * credential may not be set at this time, if the page-in
1348 * is not the result of a mapping established via mmap().
1349 *
1350 * In both these cases, this will be triggered from the paging
1351 * path, which will instead use the credential of the current
1352 * process, which in this case is either the dynamic_pager or
1353 * the kernel task, both of which utilize "root" credentials.
1354 *
1355 * This may potentially permit operations to occur which should
1356 * be denied, or it may cause to be denied operations which
1357 * should be permitted, depending on the configuration of the NFS
1358 * server.
1359 */
1360 int
ubc_setthreadcred(struct vnode * vp,proc_t p,thread_t thread)1361 ubc_setthreadcred(struct vnode *vp, proc_t p, thread_t thread)
1362 {
1363 struct ubc_info *uip;
1364 thread_ro_t tro = get_thread_ro(thread);
1365
1366 if (!UBCINFOEXISTS(vp)) {
1367 return 1;
1368 }
1369
1370 assert(thread == current_thread());
1371
1372 vnode_lock(vp);
1373
1374 uip = vp->v_ubcinfo;
1375
1376 if (!IS_VALID_CRED(uip->ui_ucred)) {
1377 /* use per-thread cred, if assumed identity, else proc cred */
1378 if (tro->tro_flags & TRO_SETUID) {
1379 uip->ui_ucred = tro->tro_cred;
1380 kauth_cred_ref(uip->ui_ucred);
1381 } else {
1382 uip->ui_ucred = kauth_cred_proc_ref(p);
1383 }
1384 }
1385 vnode_unlock(vp);
1386
1387 return 0;
1388 }
1389
1390
1391 /*
1392 * ubc_setcred
1393 *
1394 * If they are not already set, set the credentials of the ubc_info structure
1395 * associated with the vnode to those of the process; otherwise leave them
1396 * alone.
1397 *
1398 * Parameters: vp The vnode whose ubc_info creds are to
1399 * be set
1400 * p The process whose credentials are to
1401 * be used
1402 *
1403 * Returns: 0 This vnode has no associated ubc_info
1404 * 1 Success
1405 *
1406 * Notes: The return values for this function are inverted from nearly
1407 * all other uses in the kernel.
1408 *
1409 * See also ubc_setthreadcred(), above.
1410 *
1411 * This function is considered deprecated, and generally should
1412 * not be used, as it is incompatible with per-thread credentials;
1413 * it exists for legacy KPI reasons.
1414 *
1415 * DEPRECATION: ubc_setcred() is being deprecated. Please use
1416 * ubc_setthreadcred() instead.
1417 */
1418 int
ubc_setcred(struct vnode * vp,proc_t p)1419 ubc_setcred(struct vnode *vp, proc_t p)
1420 {
1421 struct ubc_info *uip;
1422 kauth_cred_t credp;
1423
1424 /* If there is no ubc_info, deny the operation */
1425 if (!UBCINFOEXISTS(vp)) {
1426 return 0;
1427 }
1428
1429 /*
1430 * Check to see if there is already a credential reference in the
1431 * ubc_info; if there is not, take one on the supplied credential.
1432 */
1433 vnode_lock(vp);
1434 uip = vp->v_ubcinfo;
1435 credp = uip->ui_ucred;
1436 if (!IS_VALID_CRED(credp)) {
1437 uip->ui_ucred = kauth_cred_proc_ref(p);
1438 }
1439 vnode_unlock(vp);
1440
1441 return 1;
1442 }
1443
1444 /*
1445 * ubc_getpager
1446 *
1447 * Get the pager associated with the ubc_info associated with the vnode.
1448 *
1449 * Parameters: vp The vnode to obtain the pager from
1450 *
1451 * Returns: !VNODE_PAGER_NULL The memory_object_t for the pager
1452 * VNODE_PAGER_NULL There is no ubc_info for this vnode
1453 *
1454 * Notes: For each vnode that has a ubc_info associated with it, that
1455 * ubc_info SHALL have a pager associated with it, so in the
1456 * normal case, it's impossible to return VNODE_PAGER_NULL for
1457 * a vnode with an associated ubc_info.
1458 */
1459 __private_extern__ memory_object_t
ubc_getpager(struct vnode * vp)1460 ubc_getpager(struct vnode *vp)
1461 {
1462 if (UBCINFOEXISTS(vp)) {
1463 return vp->v_ubcinfo->ui_pager;
1464 }
1465
1466 return 0;
1467 }
1468
1469
1470 /*
1471 * ubc_getobject
1472 *
1473 * Get the memory object control associated with the ubc_info associated with
1474 * the vnode
1475 *
1476 * Parameters: vp The vnode to obtain the memory object
1477 * from
1478 * flags DEPRECATED
1479 *
1480 * Returns: !MEMORY_OBJECT_CONTROL_NULL
1481 * MEMORY_OBJECT_CONTROL_NULL
1482 *
1483 * Notes: Historically, if the flags were not "do not reactivate", this
1484 * function would look up the memory object using the pager if
1485 * it did not exist (this could be the case if the vnode had
1486 * been previously reactivated). The flags would also permit a
1487 * hold to be requested, which would have created an object
1488 * reference, if one had not already existed. This usage is
1489 * deprecated, as it would permit a race between finding and
1490 * taking the reference vs. a single reference being dropped in
1491 * another thread.
1492 */
1493 memory_object_control_t
ubc_getobject(struct vnode * vp,__unused int flags)1494 ubc_getobject(struct vnode *vp, __unused int flags)
1495 {
1496 if (UBCINFOEXISTS(vp)) {
1497 return vp->v_ubcinfo->ui_control;
1498 }
1499
1500 return MEMORY_OBJECT_CONTROL_NULL;
1501 }
1502
1503 /*
1504 * ubc_blktooff
1505 *
1506 * Convert a given block number to a memory backing object (file) offset for a
1507 * given vnode
1508 *
1509 * Parameters: vp The vnode in which the block is located
1510 * blkno The block number to convert
1511 *
1512 * Returns: !-1 The offset into the backing object
1513 * -1 There is no ubc_info associated with
1514 * the vnode
1515 * -1 An error occurred in the underlying VFS
1516 * while translating the block to an
1517 * offset; the most likely cause is that
1518 * the caller specified a block past the
1519 * end of the file, but this could also be
1520 * any other error from VNOP_BLKTOOFF().
1521 *
1522 * Note: Representing the error in band loses some information, but does
1523 * not occlude a valid offset, since an off_t of -1 is normally
1524 * used to represent EOF. If we had a more reliable constant in
1525 * our header files for it (i.e. explicitly cast to an off_t), we
1526 * would use it here instead.
1527 */
1528 off_t
ubc_blktooff(vnode_t vp,daddr64_t blkno)1529 ubc_blktooff(vnode_t vp, daddr64_t blkno)
1530 {
1531 off_t file_offset = -1;
1532 int error;
1533
1534 if (UBCINFOEXISTS(vp)) {
1535 error = VNOP_BLKTOOFF(vp, blkno, &file_offset);
1536 if (error) {
1537 file_offset = -1;
1538 }
1539 }
1540
1541 return file_offset;
1542 }
1543
1544
1545 /*
1546 * ubc_offtoblk
1547 *
1548 * Convert a given offset in a memory backing object into a block number for a
1549 * given vnode
1550 *
1551 * Parameters: vp The vnode in which the offset is
1552 * located
1553 * offset The offset into the backing object
1554 *
1555 * Returns: !-1 The returned block number
1556 * -1 There is no ubc_info associated with
1557 * the vnode
1558 * -1 An error occurred in the underlying VFS
1559 * while translating the block to an
1560 * offset; the most likely cause is that
1561 * the caller specified a block past the
1562 * end of the file, but this could also be
1563 * any other error from VNOP_OFFTOBLK().
1564 *
1565 * Note: Representing the error in band loses some information, but does
1566 * not occlude a valid block number, since block numbers exceed
1567 * the valid range for offsets, due to their relative sizes. If
1568 * we had a more reliable constant than -1 in our header files
1569 * for it (i.e. explicitly cast to an daddr64_t), we would use it
1570 * here instead.
1571 */
1572 daddr64_t
ubc_offtoblk(vnode_t vp,off_t offset)1573 ubc_offtoblk(vnode_t vp, off_t offset)
1574 {
1575 daddr64_t blkno = -1;
1576 int error = 0;
1577
1578 if (UBCINFOEXISTS(vp)) {
1579 error = VNOP_OFFTOBLK(vp, offset, &blkno);
1580 if (error) {
1581 blkno = -1;
1582 }
1583 }
1584
1585 return blkno;
1586 }
1587
1588
1589 /*
1590 * ubc_pages_resident
1591 *
1592 * Determine whether or not a given vnode has pages resident via the memory
1593 * object control associated with the ubc_info associated with the vnode
1594 *
1595 * Parameters: vp The vnode we want to know about
1596 *
1597 * Returns: 1 Yes
1598 * 0 No
1599 */
1600 int
ubc_pages_resident(vnode_t vp)1601 ubc_pages_resident(vnode_t vp)
1602 {
1603 kern_return_t kret;
1604 boolean_t has_pages_resident;
1605
1606 if (!UBCINFOEXISTS(vp)) {
1607 return 0;
1608 }
1609
1610 /*
1611 * The following call may fail if an invalid ui_control is specified,
1612 * or if there is no VM object associated with the control object. In
1613 * either case, reacting to it as if there were no pages resident will
1614 * result in correct behavior.
1615 */
1616 kret = memory_object_pages_resident(vp->v_ubcinfo->ui_control, &has_pages_resident);
1617
1618 if (kret != KERN_SUCCESS) {
1619 return 0;
1620 }
1621
1622 if (has_pages_resident == TRUE) {
1623 return 1;
1624 }
1625
1626 return 0;
1627 }
1628
1629 /*
1630 * ubc_msync
1631 *
1632 * Clean and/or invalidate a range in the memory object that backs this vnode
1633 *
1634 * Parameters: vp The vnode whose associated ubc_info's
1635 * associated memory object is to have a
1636 * range invalidated within it
1637 * beg_off The start of the range, as an offset
1638 * end_off The end of the range, as an offset
1639 * resid_off The address of an off_t supplied by the
1640 * caller; may be set to NULL to ignore
1641 * flags See ubc_msync_internal()
1642 *
1643 * Returns: 0 Success
1644 * !0 Failure; an errno is returned
1645 *
1646 * Implicit Returns:
1647 * *resid_off, modified If non-NULL, the contents are ALWAYS
1648 * modified; they are initialized to the
1649 * beg_off, and in case of an I/O error,
1650 * the difference between beg_off and the
1651 * current value will reflect what was
1652 * able to be written before the error
1653 * occurred. If no error is returned, the
1654 * value of the resid_off is undefined; do
1655 * NOT use it in place of end_off if you
1656 * intend to increment from the end of the
1657 * last call and call iteratively.
1658 *
1659 * Notes: see ubc_msync_internal() for more detailed information.
1660 *
1661 */
1662 errno_t
ubc_msync(vnode_t vp,off_t beg_off,off_t end_off,off_t * resid_off,int flags)1663 ubc_msync(vnode_t vp, off_t beg_off, off_t end_off, off_t *resid_off, int flags)
1664 {
1665 int retval;
1666 int io_errno = 0;
1667
1668 if (resid_off) {
1669 *resid_off = beg_off;
1670 }
1671
1672 retval = ubc_msync_internal(vp, beg_off, end_off, resid_off, flags, &io_errno);
1673
1674 if (retval == 0 && io_errno == 0) {
1675 return EINVAL;
1676 }
1677 return io_errno;
1678 }
1679
1680
1681 /*
1682 * ubc_msync_internal
1683 *
1684 * Clean and/or invalidate a range in the memory object that backs this vnode
1685 *
1686 * Parameters: vp The vnode whose associated ubc_info's
1687 * associated memory object is to have a
1688 * range invalidated within it
1689 * beg_off The start of the range, as an offset
1690 * end_off The end of the range, as an offset
1691 * resid_off The address of an off_t supplied by the
1692 * caller; may be set to NULL to ignore
1693 * flags MUST contain at least one of the flags
1694 * UBC_INVALIDATE, UBC_PUSHDIRTY, or
1695 * UBC_PUSHALL; if UBC_PUSHDIRTY is used,
1696 * UBC_SYNC may also be specified to cause
1697 * this function to block until the
1698 * operation is complete. The behavior
1699 * of UBC_SYNC is otherwise undefined.
1700 * io_errno The address of an int to contain the
1701 * errno from a failed I/O operation, if
1702 * one occurs; may be set to NULL to
1703 * ignore
1704 *
1705 * Returns: 1 Success
1706 * 0 Failure
1707 *
1708 * Implicit Returns:
1709 * *resid_off, modified The contents of this offset MAY be
1710 * modified; in case of an I/O error, the
1711 * difference between beg_off and the
1712 * current value will reflect what was
1713 * able to be written before the error
1714 * occurred.
1715 * *io_errno, modified The contents of this offset are set to
1716 * an errno, if an error occurs; if the
1717 * caller supplies an io_errno parameter,
1718 * they should be careful to initialize it
1719 * to 0 before calling this function to
1720 * enable them to distinguish an error
1721 * with a valid *resid_off from an invalid
1722 * one, and to avoid potentially falsely
1723 * reporting an error, depending on use.
1724 *
1725 * Notes: If there is no ubc_info associated with the vnode supplied,
1726 * this function immediately returns success.
1727 *
1728 * If the value of end_off is less than or equal to beg_off, this
1729 * function immediately returns success; that is, end_off is NOT
1730 * inclusive.
1731 *
1732 * IMPORTANT: one of the flags UBC_INVALIDATE, UBC_PUSHDIRTY, or
1733 * UBC_PUSHALL MUST be specified; that is, it is NOT possible to
1734 * attempt to block on in-progress I/O by calling this function
1735 * with UBC_PUSHDIRTY, and then later call it with just UBC_SYNC
1736 * in order to block pending on the I/O already in progress.
1737 *
1738 * The start offset is truncated to the page boundary and the
1739 * size is adjusted to include the last page in the range; that
1740 * is, end_off on exactly a page boundary will not change if it
1741 * is rounded, and the range of bytes written will be from the
1742 * truncate beg_off to the rounded (end_off - 1).
1743 */
1744 static int
ubc_msync_internal(vnode_t vp,off_t beg_off,off_t end_off,off_t * resid_off,int flags,int * io_errno)1745 ubc_msync_internal(vnode_t vp, off_t beg_off, off_t end_off, off_t *resid_off, int flags, int *io_errno)
1746 {
1747 memory_object_size_t tsize;
1748 kern_return_t kret;
1749 int request_flags = 0;
1750 int flush_flags = MEMORY_OBJECT_RETURN_NONE;
1751
1752 if (!UBCINFOEXISTS(vp)) {
1753 return 0;
1754 }
1755 if ((flags & (UBC_INVALIDATE | UBC_PUSHDIRTY | UBC_PUSHALL)) == 0) {
1756 return 0;
1757 }
1758 if (end_off <= beg_off) {
1759 return 1;
1760 }
1761
1762 if (flags & UBC_INVALIDATE) {
1763 /*
1764 * discard the resident pages
1765 */
1766 request_flags = (MEMORY_OBJECT_DATA_FLUSH | MEMORY_OBJECT_DATA_NO_CHANGE);
1767 }
1768
1769 if (flags & UBC_SYNC) {
1770 /*
1771 * wait for all the I/O to complete before returning
1772 */
1773 request_flags |= MEMORY_OBJECT_IO_SYNC;
1774 }
1775
1776 if (flags & UBC_PUSHDIRTY) {
1777 /*
1778 * we only return the dirty pages in the range
1779 */
1780 flush_flags = MEMORY_OBJECT_RETURN_DIRTY;
1781 }
1782
1783 if (flags & UBC_PUSHALL) {
1784 /*
1785 * then return all the interesting pages in the range (both
1786 * dirty and precious) to the pager
1787 */
1788 flush_flags = MEMORY_OBJECT_RETURN_ALL;
1789 }
1790
1791 beg_off = trunc_page_64(beg_off);
1792 end_off = round_page_64(end_off);
1793 tsize = (memory_object_size_t)end_off - beg_off;
1794
1795 /* flush and/or invalidate pages in the range requested */
1796 kret = memory_object_lock_request(vp->v_ubcinfo->ui_control,
1797 beg_off, tsize,
1798 (memory_object_offset_t *)resid_off,
1799 io_errno, flush_flags, request_flags,
1800 VM_PROT_NO_CHANGE);
1801
1802 return (kret == KERN_SUCCESS) ? 1 : 0;
1803 }
1804
1805
1806 /*
1807 * ubc_map
1808 *
1809 * Explicitly map a vnode that has an associate ubc_info, and add a reference
1810 * to it for the ubc system, if there isn't one already, so it will not be
1811 * recycled while it's in use, and set flags on the ubc_info to indicate that
1812 * we have done this
1813 *
1814 * Parameters: vp The vnode to map
1815 * flags The mapping flags for the vnode; this
1816 * will be a combination of one or more of
1817 * PROT_READ, PROT_WRITE, and PROT_EXEC
1818 *
1819 * Returns: 0 Success
1820 * EPERM Permission was denied
1821 *
1822 * Notes: An I/O reference on the vnode must already be held on entry
1823 *
1824 * If there is no ubc_info associated with the vnode, this function
1825 * will return success.
1826 *
1827 * If a permission error occurs, this function will return
1828 * failure; all other failures will cause this function to return
1829 * success.
1830 *
1831 * IMPORTANT: This is an internal use function, and its symbols
1832 * are not exported, hence its error checking is not very robust.
1833 * It is primarily used by:
1834 *
1835 * o mmap(), when mapping a file
1836 * o When mapping a shared file (a shared library in the
1837 * shared segment region)
1838 * o When loading a program image during the exec process
1839 *
1840 * ...all of these uses ignore the return code, and any fault that
1841 * results later because of a failure is handled in the fix-up path
1842 * of the fault handler. The interface exists primarily as a
1843 * performance hint.
1844 *
1845 * Given that third party implementation of the type of interfaces
1846 * that would use this function, such as alternative executable
1847 * formats, etc., are unsupported, this function is not exported
1848 * for general use.
1849 *
1850 * The extra reference is held until the VM system unmaps the
1851 * vnode from its own context to maintain a vnode reference in
1852 * cases like open()/mmap()/close(), which leave the backing
1853 * object referenced by a mapped memory region in a process
1854 * address space.
1855 */
1856 __private_extern__ int
ubc_map(vnode_t vp,int flags)1857 ubc_map(vnode_t vp, int flags)
1858 {
1859 struct ubc_info *uip;
1860 int error = 0;
1861 int need_ref = 0;
1862 int need_wakeup = 0;
1863
1864 if (UBCINFOEXISTS(vp)) {
1865 vnode_lock(vp);
1866 uip = vp->v_ubcinfo;
1867
1868 while (ISSET(uip->ui_flags, UI_MAPBUSY)) {
1869 SET(uip->ui_flags, UI_MAPWAITING);
1870 (void) msleep(&uip->ui_flags, &vp->v_lock,
1871 PRIBIO, "ubc_map", NULL);
1872 }
1873 SET(uip->ui_flags, UI_MAPBUSY);
1874 vnode_unlock(vp);
1875
1876 error = VNOP_MMAP(vp, flags, vfs_context_current());
1877
1878 /*
1879 * rdar://problem/22587101 required that we stop propagating
1880 * EPERM up the stack. Otherwise, we would have to funnel up
1881 * the error at all the call sites for memory_object_map().
1882 * The risk is in having to undo the map/object/entry state at
1883 * all these call sites. It would also affect more than just mmap()
1884 * e.g. vm_remap().
1885 *
1886 * if (error != EPERM)
1887 * error = 0;
1888 */
1889
1890 error = 0;
1891
1892 vnode_lock_spin(vp);
1893
1894 if (error == 0) {
1895 if (!ISSET(uip->ui_flags, UI_ISMAPPED)) {
1896 need_ref = 1;
1897 }
1898 SET(uip->ui_flags, (UI_WASMAPPED | UI_ISMAPPED));
1899 if (flags & PROT_WRITE) {
1900 SET(uip->ui_flags, UI_MAPPEDWRITE);
1901 }
1902 }
1903 CLR(uip->ui_flags, UI_MAPBUSY);
1904
1905 if (ISSET(uip->ui_flags, UI_MAPWAITING)) {
1906 CLR(uip->ui_flags, UI_MAPWAITING);
1907 need_wakeup = 1;
1908 }
1909 vnode_unlock(vp);
1910
1911 if (need_wakeup) {
1912 wakeup(&uip->ui_flags);
1913 }
1914
1915 if (need_ref) {
1916 /*
1917 * Make sure we get a ref as we can't unwind from here
1918 */
1919 if (vnode_ref_ext(vp, 0, VNODE_REF_FORCE)) {
1920 panic("%s : VNODE_REF_FORCE failed", __FUNCTION__);
1921 }
1922 /*
1923 * Vnodes that are on "unreliable" media (like disk
1924 * images, network filesystems, 3rd-party filesystems,
1925 * and possibly external devices) could see their
1926 * contents be changed via the backing store without
1927 * triggering copy-on-write, so we can't fully rely
1928 * on copy-on-write and might have to resort to
1929 * copy-on-read to protect "privileged" processes and
1930 * prevent privilege escalation.
1931 *
1932 * The root filesystem is considered "reliable" because
1933 * there's not much point in trying to protect
1934 * ourselves from such a vulnerability and the extra
1935 * cost of copy-on-read (CPU time and memory pressure)
1936 * could result in some serious regressions.
1937 */
1938 if (vp->v_mount != NULL &&
1939 ((vp->v_mount->mnt_flag & MNT_ROOTFS) ||
1940 vnode_on_reliable_media(vp))) {
1941 /*
1942 * This vnode is deemed "reliable" so mark
1943 * its VM object as "trusted".
1944 */
1945 memory_object_mark_trusted(uip->ui_control);
1946 } else {
1947 // printf("BUGGYCOW: %s:%d vp %p \"%s\" in mnt %p \"%s\" is untrusted\n", __FUNCTION__, __LINE__, vp, vp->v_name, vp->v_mount, vp->v_mount->mnt_vnodecovered->v_name);
1948 }
1949 }
1950 }
1951 return error;
1952 }
1953
1954
1955 /*
1956 * ubc_destroy_named
1957 *
1958 * Destroy the named memory object associated with the ubc_info control object
1959 * associated with the designated vnode, if there is a ubc_info associated
1960 * with the vnode, and a control object is associated with it
1961 *
1962 * Parameters: vp The designated vnode
1963 *
1964 * Returns: (void)
1965 *
1966 * Notes: This function is called on vnode termination for all vnodes,
1967 * and must therefore not assume that there is a ubc_info that is
1968 * associated with the vnode, nor that there is a control object
1969 * associated with the ubc_info.
1970 *
1971 * If all the conditions necessary are present, this function
1972 * calls memory_object_destory(), which will in turn end up
1973 * calling ubc_unmap() to release any vnode references that were
1974 * established via ubc_map().
1975 *
1976 * IMPORTANT: This is an internal use function that is used
1977 * exclusively by the internal use function vclean().
1978 */
1979 __private_extern__ void
ubc_destroy_named(vnode_t vp)1980 ubc_destroy_named(vnode_t vp)
1981 {
1982 memory_object_control_t control;
1983 struct ubc_info *uip;
1984 kern_return_t kret;
1985
1986 if (UBCINFOEXISTS(vp)) {
1987 uip = vp->v_ubcinfo;
1988
1989 /* Terminate the memory object */
1990 control = ubc_getobject(vp, UBC_HOLDOBJECT);
1991 if (control != MEMORY_OBJECT_CONTROL_NULL) {
1992 kret = memory_object_destroy(control, 0);
1993 if (kret != KERN_SUCCESS) {
1994 panic("ubc_destroy_named: memory_object_destroy failed");
1995 }
1996 }
1997 }
1998 }
1999
2000
2001 /*
2002 * ubc_isinuse
2003 *
2004 * Determine whether or not a vnode is currently in use by ubc at a level in
2005 * excess of the requested busycount
2006 *
2007 * Parameters: vp The vnode to check
2008 * busycount The threshold busy count, used to bias
2009 * the count usually already held by the
2010 * caller to avoid races
2011 *
2012 * Returns: 1 The vnode is in use over the threshold
2013 * 0 The vnode is not in use over the
2014 * threshold
2015 *
2016 * Notes: Because the vnode is only held locked while actually asking
2017 * the use count, this function only represents a snapshot of the
2018 * current state of the vnode. If more accurate information is
2019 * required, an additional busycount should be held by the caller
2020 * and a non-zero busycount used.
2021 *
2022 * If there is no ubc_info associated with the vnode, this
2023 * function will report that the vnode is not in use by ubc.
2024 */
2025 int
ubc_isinuse(struct vnode * vp,int busycount)2026 ubc_isinuse(struct vnode *vp, int busycount)
2027 {
2028 if (!UBCINFOEXISTS(vp)) {
2029 return 0;
2030 }
2031 return ubc_isinuse_locked(vp, busycount, 0);
2032 }
2033
2034
2035 /*
2036 * ubc_isinuse_locked
2037 *
2038 * Determine whether or not a vnode is currently in use by ubc at a level in
2039 * excess of the requested busycount
2040 *
2041 * Parameters: vp The vnode to check
2042 * busycount The threshold busy count, used to bias
2043 * the count usually already held by the
2044 * caller to avoid races
2045 * locked True if the vnode is already locked by
2046 * the caller
2047 *
2048 * Returns: 1 The vnode is in use over the threshold
2049 * 0 The vnode is not in use over the
2050 * threshold
2051 *
2052 * Notes: If the vnode is not locked on entry, it is locked while
2053 * actually asking the use count. If this is the case, this
2054 * function only represents a snapshot of the current state of
2055 * the vnode. If more accurate information is required, the
2056 * vnode lock should be held by the caller, otherwise an
2057 * additional busycount should be held by the caller and a
2058 * non-zero busycount used.
2059 *
2060 * If there is no ubc_info associated with the vnode, this
2061 * function will report that the vnode is not in use by ubc.
2062 */
2063 int
ubc_isinuse_locked(struct vnode * vp,int busycount,int locked)2064 ubc_isinuse_locked(struct vnode *vp, int busycount, int locked)
2065 {
2066 int retval = 0;
2067
2068
2069 if (!locked) {
2070 vnode_lock_spin(vp);
2071 }
2072
2073 if ((vp->v_usecount - vp->v_kusecount) > busycount) {
2074 retval = 1;
2075 }
2076
2077 if (!locked) {
2078 vnode_unlock(vp);
2079 }
2080 return retval;
2081 }
2082
2083
2084 /*
2085 * ubc_unmap
2086 *
2087 * Reverse the effects of a ubc_map() call for a given vnode
2088 *
2089 * Parameters: vp vnode to unmap from ubc
2090 *
2091 * Returns: (void)
2092 *
2093 * Notes: This is an internal use function used by vnode_pager_unmap().
2094 * It will attempt to obtain a reference on the supplied vnode,
2095 * and if it can do so, and there is an associated ubc_info, and
2096 * the flags indicate that it was mapped via ubc_map(), then the
2097 * flag is cleared, the mapping removed, and the reference taken
2098 * by ubc_map() is released.
2099 *
2100 * IMPORTANT: This MUST only be called by the VM
2101 * to prevent race conditions.
2102 */
2103 __private_extern__ void
ubc_unmap(struct vnode * vp)2104 ubc_unmap(struct vnode *vp)
2105 {
2106 struct ubc_info *uip;
2107 int need_rele = 0;
2108 int need_wakeup = 0;
2109
2110 if (vnode_getwithref(vp)) {
2111 return;
2112 }
2113
2114 if (UBCINFOEXISTS(vp)) {
2115 bool want_fsevent = false;
2116
2117 vnode_lock(vp);
2118 uip = vp->v_ubcinfo;
2119
2120 while (ISSET(uip->ui_flags, UI_MAPBUSY)) {
2121 SET(uip->ui_flags, UI_MAPWAITING);
2122 (void) msleep(&uip->ui_flags, &vp->v_lock,
2123 PRIBIO, "ubc_unmap", NULL);
2124 }
2125 SET(uip->ui_flags, UI_MAPBUSY);
2126
2127 if (ISSET(uip->ui_flags, UI_ISMAPPED)) {
2128 if (ISSET(uip->ui_flags, UI_MAPPEDWRITE)) {
2129 want_fsevent = true;
2130 }
2131
2132 need_rele = 1;
2133
2134 /*
2135 * We want to clear the mapped flags after we've called
2136 * VNOP_MNOMAP to avoid certain races and allow
2137 * VNOP_MNOMAP to call ubc_is_mapped_writable.
2138 */
2139 }
2140 vnode_unlock(vp);
2141
2142 if (need_rele) {
2143 vfs_context_t ctx = vfs_context_current();
2144
2145 (void)VNOP_MNOMAP(vp, ctx);
2146
2147 #if CONFIG_FSE
2148 /*
2149 * Why do we want an fsevent here? Normally the
2150 * content modified fsevent is posted when a file is
2151 * closed and only if it's written to via conventional
2152 * means. It's perfectly legal to close a file and
2153 * keep your mappings and we don't currently track
2154 * whether it was written to via a mapping.
2155 * Therefore, we need to post an fsevent here if the
2156 * file was mapped writable. This may result in false
2157 * events, i.e. we post a notification when nothing
2158 * has really changed.
2159 */
2160 if (want_fsevent && need_fsevent(FSE_CONTENT_MODIFIED, vp)) {
2161 add_fsevent(FSE_CONTENT_MODIFIED_NO_HLINK, ctx,
2162 FSE_ARG_VNODE, vp,
2163 FSE_ARG_DONE);
2164 }
2165 #endif
2166
2167 vnode_rele(vp);
2168 }
2169
2170 vnode_lock_spin(vp);
2171
2172 if (need_rele) {
2173 CLR(uip->ui_flags, UI_ISMAPPED | UI_MAPPEDWRITE);
2174 }
2175
2176 CLR(uip->ui_flags, UI_MAPBUSY);
2177
2178 if (ISSET(uip->ui_flags, UI_MAPWAITING)) {
2179 CLR(uip->ui_flags, UI_MAPWAITING);
2180 need_wakeup = 1;
2181 }
2182 vnode_unlock(vp);
2183
2184 if (need_wakeup) {
2185 wakeup(&uip->ui_flags);
2186 }
2187 }
2188 /*
2189 * the drop of the vnode ref will cleanup
2190 */
2191 vnode_put(vp);
2192 }
2193
2194
2195 /*
2196 * ubc_page_op
2197 *
2198 * Manipulate individual page state for a vnode with an associated ubc_info
2199 * with an associated memory object control.
2200 *
2201 * Parameters: vp The vnode backing the page
2202 * f_offset A file offset interior to the page
2203 * ops The operations to perform, as a bitmap
2204 * (see below for more information)
2205 * phys_entryp The address of a ppnum_t; may be NULL
2206 * to ignore
2207 * flagsp A pointer to an int to contain flags;
2208 * may be NULL to ignore
2209 *
2210 * Returns: KERN_SUCCESS Success
2211 * KERN_INVALID_ARGUMENT If the memory object control has no VM
2212 * object associated
2213 * KERN_INVALID_OBJECT If UPL_POP_PHYSICAL and the object is
2214 * not physically contiguous
2215 * KERN_INVALID_OBJECT If !UPL_POP_PHYSICAL and the object is
2216 * physically contiguous
2217 * KERN_FAILURE If the page cannot be looked up
2218 *
2219 * Implicit Returns:
2220 * *phys_entryp (modified) If phys_entryp is non-NULL and
2221 * UPL_POP_PHYSICAL
2222 * *flagsp (modified) If flagsp is non-NULL and there was
2223 * !UPL_POP_PHYSICAL and a KERN_SUCCESS
2224 *
2225 * Notes: For object boundaries, it is considerably more efficient to
2226 * ensure that f_offset is in fact on a page boundary, as this
2227 * will avoid internal use of the hash table to identify the
2228 * page, and would therefore skip a number of early optimizations.
2229 * Since this is a page operation anyway, the caller should try
2230 * to pass only a page aligned offset because of this.
2231 *
2232 * *flagsp may be modified even if this function fails. If it is
2233 * modified, it will contain the condition of the page before the
2234 * requested operation was attempted; these will only include the
2235 * bitmap flags, and not the PL_POP_PHYSICAL, UPL_POP_DUMP,
2236 * UPL_POP_SET, or UPL_POP_CLR bits.
2237 *
2238 * The flags field may contain a specific operation, such as
2239 * UPL_POP_PHYSICAL or UPL_POP_DUMP:
2240 *
2241 * o UPL_POP_PHYSICAL Fail if not contiguous; if
2242 * *phys_entryp and successful, set
2243 * *phys_entryp
2244 * o UPL_POP_DUMP Dump the specified page
2245 *
2246 * Otherwise, it is treated as a bitmap of one or more page
2247 * operations to perform on the final memory object; allowable
2248 * bit values are:
2249 *
2250 * o UPL_POP_DIRTY The page is dirty
2251 * o UPL_POP_PAGEOUT The page is paged out
2252 * o UPL_POP_PRECIOUS The page is precious
2253 * o UPL_POP_ABSENT The page is absent
2254 * o UPL_POP_BUSY The page is busy
2255 *
2256 * If the page status is only being queried and not modified, then
2257 * not other bits should be specified. However, if it is being
2258 * modified, exactly ONE of the following bits should be set:
2259 *
2260 * o UPL_POP_SET Set the current bitmap bits
2261 * o UPL_POP_CLR Clear the current bitmap bits
2262 *
2263 * Thus to effect a combination of setting an clearing, it may be
2264 * necessary to call this function twice. If this is done, the
2265 * set should be used before the clear, since clearing may trigger
2266 * a wakeup on the destination page, and if the page is backed by
2267 * an encrypted swap file, setting will trigger the decryption
2268 * needed before the wakeup occurs.
2269 */
2270 kern_return_t
ubc_page_op(struct vnode * vp,off_t f_offset,int ops,ppnum_t * phys_entryp,int * flagsp)2271 ubc_page_op(
2272 struct vnode *vp,
2273 off_t f_offset,
2274 int ops,
2275 ppnum_t *phys_entryp,
2276 int *flagsp)
2277 {
2278 memory_object_control_t control;
2279
2280 control = ubc_getobject(vp, UBC_FLAGS_NONE);
2281 if (control == MEMORY_OBJECT_CONTROL_NULL) {
2282 return KERN_INVALID_ARGUMENT;
2283 }
2284
2285 return memory_object_page_op(control,
2286 (memory_object_offset_t)f_offset,
2287 ops,
2288 phys_entryp,
2289 flagsp);
2290 }
2291
2292
2293 /*
2294 * ubc_range_op
2295 *
2296 * Manipulate page state for a range of memory for a vnode with an associated
2297 * ubc_info with an associated memory object control, when page level state is
2298 * not required to be returned from the call (i.e. there are no phys_entryp or
2299 * flagsp parameters to this call, and it takes a range which may contain
2300 * multiple pages, rather than an offset interior to a single page).
2301 *
2302 * Parameters: vp The vnode backing the page
2303 * f_offset_beg A file offset interior to the start page
2304 * f_offset_end A file offset interior to the end page
2305 * ops The operations to perform, as a bitmap
2306 * (see below for more information)
2307 * range The address of an int; may be NULL to
2308 * ignore
2309 *
2310 * Returns: KERN_SUCCESS Success
2311 * KERN_INVALID_ARGUMENT If the memory object control has no VM
2312 * object associated
2313 * KERN_INVALID_OBJECT If the object is physically contiguous
2314 *
2315 * Implicit Returns:
2316 * *range (modified) If range is non-NULL, its contents will
2317 * be modified to contain the number of
2318 * bytes successfully operated upon.
2319 *
2320 * Notes: IMPORTANT: This function cannot be used on a range that
2321 * consists of physically contiguous pages.
2322 *
2323 * For object boundaries, it is considerably more efficient to
2324 * ensure that f_offset_beg and f_offset_end are in fact on page
2325 * boundaries, as this will avoid internal use of the hash table
2326 * to identify the page, and would therefore skip a number of
2327 * early optimizations. Since this is an operation on a set of
2328 * pages anyway, the caller should try to pass only a page aligned
2329 * offsets because of this.
2330 *
2331 * *range will be modified only if this function succeeds.
2332 *
2333 * The flags field MUST contain a specific operation; allowable
2334 * values are:
2335 *
2336 * o UPL_ROP_ABSENT Returns the extent of the range
2337 * presented which is absent, starting
2338 * with the start address presented
2339 *
2340 * o UPL_ROP_PRESENT Returns the extent of the range
2341 * presented which is present (resident),
2342 * starting with the start address
2343 * presented
2344 * o UPL_ROP_DUMP Dump the pages which are found in the
2345 * target object for the target range.
2346 *
2347 * IMPORTANT: For UPL_ROP_ABSENT and UPL_ROP_PRESENT; if there are
2348 * multiple regions in the range, only the first matching region
2349 * is returned.
2350 */
2351 kern_return_t
ubc_range_op(struct vnode * vp,off_t f_offset_beg,off_t f_offset_end,int ops,int * range)2352 ubc_range_op(
2353 struct vnode *vp,
2354 off_t f_offset_beg,
2355 off_t f_offset_end,
2356 int ops,
2357 int *range)
2358 {
2359 memory_object_control_t control;
2360
2361 control = ubc_getobject(vp, UBC_FLAGS_NONE);
2362 if (control == MEMORY_OBJECT_CONTROL_NULL) {
2363 return KERN_INVALID_ARGUMENT;
2364 }
2365
2366 return memory_object_range_op(control,
2367 (memory_object_offset_t)f_offset_beg,
2368 (memory_object_offset_t)f_offset_end,
2369 ops,
2370 range);
2371 }
2372
2373
2374 /*
2375 * ubc_create_upl
2376 *
2377 * Given a vnode, cause the population of a portion of the vm_object; based on
2378 * the nature of the request, the pages returned may contain valid data, or
2379 * they may be uninitialized.
2380 *
2381 * Parameters: vp The vnode from which to create the upl
2382 * f_offset The start offset into the backing store
2383 * represented by the vnode
2384 * bufsize The size of the upl to create
2385 * uplp Pointer to the upl_t to receive the
2386 * created upl; MUST NOT be NULL
2387 * plp Pointer to receive the internal page
2388 * list for the created upl; MAY be NULL
2389 * to ignore
2390 *
2391 * Returns: KERN_SUCCESS The requested upl has been created
2392 * KERN_INVALID_ARGUMENT The bufsize argument is not an even
2393 * multiple of the page size
2394 * KERN_INVALID_ARGUMENT There is no ubc_info associated with
2395 * the vnode, or there is no memory object
2396 * control associated with the ubc_info
2397 * memory_object_upl_request:KERN_INVALID_VALUE
2398 * The supplied upl_flags argument is
2399 * invalid
2400 * Implicit Returns:
2401 * *uplp (modified)
2402 * *plp (modified) If non-NULL, the value of *plp will be
2403 * modified to point to the internal page
2404 * list; this modification may occur even
2405 * if this function is unsuccessful, in
2406 * which case the contents may be invalid
2407 *
2408 * Note: If successful, the returned *uplp MUST subsequently be freed
2409 * via a call to ubc_upl_commit(), ubc_upl_commit_range(),
2410 * ubc_upl_abort(), or ubc_upl_abort_range().
2411 */
2412 kern_return_t
ubc_create_upl_external(struct vnode * vp,off_t f_offset,int bufsize,upl_t * uplp,upl_page_info_t ** plp,int uplflags)2413 ubc_create_upl_external(
2414 struct vnode *vp,
2415 off_t f_offset,
2416 int bufsize,
2417 upl_t *uplp,
2418 upl_page_info_t **plp,
2419 int uplflags)
2420 {
2421 return ubc_create_upl_kernel(vp, f_offset, bufsize, uplp, plp, uplflags, vm_tag_bt());
2422 }
2423
2424 kern_return_t
ubc_create_upl_kernel(struct vnode * vp,off_t f_offset,int bufsize,upl_t * uplp,upl_page_info_t ** plp,int uplflags,vm_tag_t tag)2425 ubc_create_upl_kernel(
2426 struct vnode *vp,
2427 off_t f_offset,
2428 int bufsize,
2429 upl_t *uplp,
2430 upl_page_info_t **plp,
2431 int uplflags,
2432 vm_tag_t tag)
2433 {
2434 memory_object_control_t control;
2435 kern_return_t kr;
2436
2437 if (plp != NULL) {
2438 *plp = NULL;
2439 }
2440 *uplp = NULL;
2441
2442 if (bufsize & 0xfff) {
2443 return KERN_INVALID_ARGUMENT;
2444 }
2445
2446 if (bufsize > MAX_UPL_SIZE_BYTES) {
2447 return KERN_INVALID_ARGUMENT;
2448 }
2449
2450 if (uplflags & (UPL_UBC_MSYNC | UPL_UBC_PAGEOUT | UPL_UBC_PAGEIN)) {
2451 if (uplflags & UPL_UBC_MSYNC) {
2452 uplflags &= UPL_RET_ONLY_DIRTY;
2453
2454 uplflags |= UPL_COPYOUT_FROM | UPL_CLEAN_IN_PLACE |
2455 UPL_SET_INTERNAL | UPL_SET_LITE;
2456 } else if (uplflags & UPL_UBC_PAGEOUT) {
2457 uplflags &= UPL_RET_ONLY_DIRTY;
2458
2459 if (uplflags & UPL_RET_ONLY_DIRTY) {
2460 uplflags |= UPL_NOBLOCK;
2461 }
2462
2463 uplflags |= UPL_FOR_PAGEOUT | UPL_CLEAN_IN_PLACE |
2464 UPL_COPYOUT_FROM | UPL_SET_INTERNAL | UPL_SET_LITE;
2465 } else {
2466 uplflags |= UPL_RET_ONLY_ABSENT |
2467 UPL_NO_SYNC | UPL_CLEAN_IN_PLACE |
2468 UPL_SET_INTERNAL | UPL_SET_LITE;
2469
2470 /*
2471 * if the requested size == PAGE_SIZE, we don't want to set
2472 * the UPL_NOBLOCK since we may be trying to recover from a
2473 * previous partial pagein I/O that occurred because we were low
2474 * on memory and bailed early in order to honor the UPL_NOBLOCK...
2475 * since we're only asking for a single page, we can block w/o fear
2476 * of tying up pages while waiting for more to become available
2477 */
2478 if (bufsize > PAGE_SIZE) {
2479 uplflags |= UPL_NOBLOCK;
2480 }
2481 }
2482 } else {
2483 uplflags &= ~UPL_FOR_PAGEOUT;
2484
2485 if (uplflags & UPL_WILL_BE_DUMPED) {
2486 uplflags &= ~UPL_WILL_BE_DUMPED;
2487 uplflags |= (UPL_NO_SYNC | UPL_SET_INTERNAL);
2488 } else {
2489 uplflags |= (UPL_NO_SYNC | UPL_CLEAN_IN_PLACE | UPL_SET_INTERNAL);
2490 }
2491 }
2492 control = ubc_getobject(vp, UBC_FLAGS_NONE);
2493 if (control == MEMORY_OBJECT_CONTROL_NULL) {
2494 return KERN_INVALID_ARGUMENT;
2495 }
2496
2497 kr = memory_object_upl_request(control, f_offset, bufsize, uplp, NULL, NULL, uplflags, tag);
2498 if (kr == KERN_SUCCESS && plp != NULL) {
2499 *plp = UPL_GET_INTERNAL_PAGE_LIST(*uplp);
2500 }
2501 return kr;
2502 }
2503
2504
2505 /*
2506 * ubc_upl_maxbufsize
2507 *
2508 * Return the maximum bufsize ubc_create_upl( ) will take.
2509 *
2510 * Parameters: none
2511 *
2512 * Returns: maximum size buffer (in bytes) ubc_create_upl( ) will take.
2513 */
2514 upl_size_t
ubc_upl_maxbufsize(void)2515 ubc_upl_maxbufsize(
2516 void)
2517 {
2518 return MAX_UPL_SIZE_BYTES;
2519 }
2520
2521 /*
2522 * ubc_upl_map
2523 *
2524 * Map the page list assocated with the supplied upl into the kernel virtual
2525 * address space at the virtual address indicated by the dst_addr argument;
2526 * the entire upl is mapped
2527 *
2528 * Parameters: upl The upl to map
2529 * dst_addr The address at which to map the upl
2530 *
2531 * Returns: KERN_SUCCESS The upl has been mapped
2532 * KERN_INVALID_ARGUMENT The upl is UPL_NULL
2533 * KERN_FAILURE The upl is already mapped
2534 * vm_map_enter:KERN_INVALID_ARGUMENT
2535 * A failure code from vm_map_enter() due
2536 * to an invalid argument
2537 */
2538 kern_return_t
ubc_upl_map(upl_t upl,vm_offset_t * dst_addr)2539 ubc_upl_map(
2540 upl_t upl,
2541 vm_offset_t *dst_addr)
2542 {
2543 return vm_upl_map(kernel_map, upl, dst_addr);
2544 }
2545
2546 /*
2547 * ubc_upl_map_range:- similar to ubc_upl_map but the focus is on a range
2548 * of the UPL. Takes an offset, size, and protection so that only a part
2549 * of the UPL can be mapped with the right protections.
2550 */
2551 kern_return_t
ubc_upl_map_range(upl_t upl,vm_offset_t offset_to_map,vm_size_t size_to_map,vm_prot_t prot_to_map,vm_offset_t * dst_addr)2552 ubc_upl_map_range(
2553 upl_t upl,
2554 vm_offset_t offset_to_map,
2555 vm_size_t size_to_map,
2556 vm_prot_t prot_to_map,
2557 vm_offset_t *dst_addr)
2558 {
2559 return vm_upl_map_range(kernel_map, upl, offset_to_map, size_to_map, prot_to_map, dst_addr);
2560 }
2561
2562
2563 /*
2564 * ubc_upl_unmap
2565 *
2566 * Unmap the page list assocated with the supplied upl from the kernel virtual
2567 * address space; the entire upl is unmapped.
2568 *
2569 * Parameters: upl The upl to unmap
2570 *
2571 * Returns: KERN_SUCCESS The upl has been unmapped
2572 * KERN_FAILURE The upl is not currently mapped
2573 * KERN_INVALID_ARGUMENT If the upl is UPL_NULL
2574 */
2575 kern_return_t
ubc_upl_unmap(upl_t upl)2576 ubc_upl_unmap(
2577 upl_t upl)
2578 {
2579 return vm_upl_unmap(kernel_map, upl);
2580 }
2581
2582 /*
2583 * ubc_upl_unmap_range:- similar to ubc_upl_unmap but the focus is
2584 * on part of the UPL that is mapped. The offset and size parameter
2585 * specifies what part of the UPL needs to be unmapped.
2586 *
2587 * Note: Currrently offset & size are unused as we always initiate the unmap from the
2588 * very beginning of the UPL's mapping and track the mapped size in the UPL. But we
2589 * might want to allow unmapping a UPL in the middle, for example, and we can use the
2590 * offset + size parameters for that purpose.
2591 */
2592 kern_return_t
ubc_upl_unmap_range(upl_t upl,vm_offset_t offset_to_unmap,vm_size_t size_to_unmap)2593 ubc_upl_unmap_range(
2594 upl_t upl,
2595 vm_offset_t offset_to_unmap,
2596 vm_size_t size_to_unmap)
2597 {
2598 return vm_upl_unmap_range(kernel_map, upl, offset_to_unmap, size_to_unmap);
2599 }
2600
2601
2602 /*
2603 * ubc_upl_commit
2604 *
2605 * Commit the contents of the upl to the backing store
2606 *
2607 * Parameters: upl The upl to commit
2608 *
2609 * Returns: KERN_SUCCESS The upl has been committed
2610 * KERN_INVALID_ARGUMENT The supplied upl was UPL_NULL
2611 * KERN_FAILURE The supplied upl does not represent
2612 * device memory, and the offset plus the
2613 * size would exceed the actual size of
2614 * the upl
2615 *
2616 * Notes: In practice, the only return value for this function should be
2617 * KERN_SUCCESS, unless there has been data structure corruption;
2618 * since the upl is deallocated regardless of success or failure,
2619 * there's really nothing to do about this other than panic.
2620 *
2621 * IMPORTANT: Use of this function should not be mixed with use of
2622 * ubc_upl_commit_range(), due to the unconditional deallocation
2623 * by this function.
2624 */
2625 kern_return_t
ubc_upl_commit(upl_t upl)2626 ubc_upl_commit(
2627 upl_t upl)
2628 {
2629 upl_page_info_t *pl;
2630 kern_return_t kr;
2631
2632 pl = UPL_GET_INTERNAL_PAGE_LIST(upl);
2633 kr = upl_commit(upl, pl, MAX_UPL_SIZE_BYTES >> PAGE_SHIFT);
2634 upl_deallocate(upl);
2635 return kr;
2636 }
2637
2638
2639 /*
2640 * ubc_upl_commit
2641 *
2642 * Commit the contents of the specified range of the upl to the backing store
2643 *
2644 * Parameters: upl The upl to commit
2645 * offset The offset into the upl
2646 * size The size of the region to be committed,
2647 * starting at the specified offset
2648 * flags commit type (see below)
2649 *
2650 * Returns: KERN_SUCCESS The range has been committed
2651 * KERN_INVALID_ARGUMENT The supplied upl was UPL_NULL
2652 * KERN_FAILURE The supplied upl does not represent
2653 * device memory, and the offset plus the
2654 * size would exceed the actual size of
2655 * the upl
2656 *
2657 * Notes: IMPORTANT: If the commit is successful, and the object is now
2658 * empty, the upl will be deallocated. Since the caller cannot
2659 * check that this is the case, the UPL_COMMIT_FREE_ON_EMPTY flag
2660 * should generally only be used when the offset is 0 and the size
2661 * is equal to the upl size.
2662 *
2663 * The flags argument is a bitmap of flags on the rage of pages in
2664 * the upl to be committed; allowable flags are:
2665 *
2666 * o UPL_COMMIT_FREE_ON_EMPTY Free the upl when it is
2667 * both empty and has been
2668 * successfully committed
2669 * o UPL_COMMIT_CLEAR_DIRTY Clear each pages dirty
2670 * bit; will prevent a
2671 * later pageout
2672 * o UPL_COMMIT_SET_DIRTY Set each pages dirty
2673 * bit; will cause a later
2674 * pageout
2675 * o UPL_COMMIT_INACTIVATE Clear each pages
2676 * reference bit; the page
2677 * will not be accessed
2678 * o UPL_COMMIT_ALLOW_ACCESS Unbusy each page; pages
2679 * become busy when an
2680 * IOMemoryDescriptor is
2681 * mapped or redirected,
2682 * and we have to wait for
2683 * an IOKit driver
2684 *
2685 * The flag UPL_COMMIT_NOTIFY_EMPTY is used internally, and should
2686 * not be specified by the caller.
2687 *
2688 * The UPL_COMMIT_CLEAR_DIRTY and UPL_COMMIT_SET_DIRTY flags are
2689 * mutually exclusive, and should not be combined.
2690 */
2691 kern_return_t
ubc_upl_commit_range(upl_t upl,upl_offset_t offset,upl_size_t size,int flags)2692 ubc_upl_commit_range(
2693 upl_t upl,
2694 upl_offset_t offset,
2695 upl_size_t size,
2696 int flags)
2697 {
2698 upl_page_info_t *pl;
2699 boolean_t empty;
2700 kern_return_t kr;
2701
2702 if (flags & UPL_COMMIT_FREE_ON_EMPTY) {
2703 flags |= UPL_COMMIT_NOTIFY_EMPTY;
2704 }
2705
2706 if (flags & UPL_COMMIT_KERNEL_ONLY_FLAGS) {
2707 return KERN_INVALID_ARGUMENT;
2708 }
2709
2710 pl = UPL_GET_INTERNAL_PAGE_LIST(upl);
2711
2712 kr = upl_commit_range(upl, offset, size, flags,
2713 pl, MAX_UPL_SIZE_BYTES >> PAGE_SHIFT, &empty);
2714
2715 if ((flags & UPL_COMMIT_FREE_ON_EMPTY) && empty) {
2716 upl_deallocate(upl);
2717 }
2718
2719 return kr;
2720 }
2721
2722
2723 /*
2724 * ubc_upl_abort_range
2725 *
2726 * Abort the contents of the specified range of the specified upl
2727 *
2728 * Parameters: upl The upl to abort
2729 * offset The offset into the upl
2730 * size The size of the region to be aborted,
2731 * starting at the specified offset
2732 * abort_flags abort type (see below)
2733 *
2734 * Returns: KERN_SUCCESS The range has been aborted
2735 * KERN_INVALID_ARGUMENT The supplied upl was UPL_NULL
2736 * KERN_FAILURE The supplied upl does not represent
2737 * device memory, and the offset plus the
2738 * size would exceed the actual size of
2739 * the upl
2740 *
2741 * Notes: IMPORTANT: If the abort is successful, and the object is now
2742 * empty, the upl will be deallocated. Since the caller cannot
2743 * check that this is the case, the UPL_ABORT_FREE_ON_EMPTY flag
2744 * should generally only be used when the offset is 0 and the size
2745 * is equal to the upl size.
2746 *
2747 * The abort_flags argument is a bitmap of flags on the range of
2748 * pages in the upl to be aborted; allowable flags are:
2749 *
2750 * o UPL_ABORT_FREE_ON_EMPTY Free the upl when it is both
2751 * empty and has been successfully
2752 * aborted
2753 * o UPL_ABORT_RESTART The operation must be restarted
2754 * o UPL_ABORT_UNAVAILABLE The pages are unavailable
2755 * o UPL_ABORT_ERROR An I/O error occurred
2756 * o UPL_ABORT_DUMP_PAGES Just free the pages
2757 * o UPL_ABORT_NOTIFY_EMPTY RESERVED
2758 * o UPL_ABORT_ALLOW_ACCESS RESERVED
2759 *
2760 * The UPL_ABORT_NOTIFY_EMPTY is an internal use flag and should
2761 * not be specified by the caller. It is intended to fulfill the
2762 * same role as UPL_COMMIT_NOTIFY_EMPTY does in the function
2763 * ubc_upl_commit_range(), but is never referenced internally.
2764 *
2765 * The UPL_ABORT_ALLOW_ACCESS is defined, but neither set nor
2766 * referenced; do not use it.
2767 */
2768 kern_return_t
ubc_upl_abort_range(upl_t upl,upl_offset_t offset,upl_size_t size,int abort_flags)2769 ubc_upl_abort_range(
2770 upl_t upl,
2771 upl_offset_t offset,
2772 upl_size_t size,
2773 int abort_flags)
2774 {
2775 kern_return_t kr;
2776 boolean_t empty = FALSE;
2777
2778 if (abort_flags & UPL_ABORT_FREE_ON_EMPTY) {
2779 abort_flags |= UPL_ABORT_NOTIFY_EMPTY;
2780 }
2781
2782 kr = upl_abort_range(upl, offset, size, abort_flags, &empty);
2783
2784 if ((abort_flags & UPL_ABORT_FREE_ON_EMPTY) && empty) {
2785 upl_deallocate(upl);
2786 }
2787
2788 return kr;
2789 }
2790
2791
2792 /*
2793 * ubc_upl_abort
2794 *
2795 * Abort the contents of the specified upl
2796 *
2797 * Parameters: upl The upl to abort
2798 * abort_type abort type (see below)
2799 *
2800 * Returns: KERN_SUCCESS The range has been aborted
2801 * KERN_INVALID_ARGUMENT The supplied upl was UPL_NULL
2802 * KERN_FAILURE The supplied upl does not represent
2803 * device memory, and the offset plus the
2804 * size would exceed the actual size of
2805 * the upl
2806 *
2807 * Notes: IMPORTANT: If the abort is successful, and the object is now
2808 * empty, the upl will be deallocated. Since the caller cannot
2809 * check that this is the case, the UPL_ABORT_FREE_ON_EMPTY flag
2810 * should generally only be used when the offset is 0 and the size
2811 * is equal to the upl size.
2812 *
2813 * The abort_type is a bitmap of flags on the range of
2814 * pages in the upl to be aborted; allowable flags are:
2815 *
2816 * o UPL_ABORT_FREE_ON_EMPTY Free the upl when it is both
2817 * empty and has been successfully
2818 * aborted
2819 * o UPL_ABORT_RESTART The operation must be restarted
2820 * o UPL_ABORT_UNAVAILABLE The pages are unavailable
2821 * o UPL_ABORT_ERROR An I/O error occurred
2822 * o UPL_ABORT_DUMP_PAGES Just free the pages
2823 * o UPL_ABORT_NOTIFY_EMPTY RESERVED
2824 * o UPL_ABORT_ALLOW_ACCESS RESERVED
2825 *
2826 * The UPL_ABORT_NOTIFY_EMPTY is an internal use flag and should
2827 * not be specified by the caller. It is intended to fulfill the
2828 * same role as UPL_COMMIT_NOTIFY_EMPTY does in the function
2829 * ubc_upl_commit_range(), but is never referenced internally.
2830 *
2831 * The UPL_ABORT_ALLOW_ACCESS is defined, but neither set nor
2832 * referenced; do not use it.
2833 */
2834 kern_return_t
ubc_upl_abort(upl_t upl,int abort_type)2835 ubc_upl_abort(
2836 upl_t upl,
2837 int abort_type)
2838 {
2839 kern_return_t kr;
2840
2841 kr = upl_abort(upl, abort_type);
2842 upl_deallocate(upl);
2843 return kr;
2844 }
2845
2846
2847 /*
2848 * ubc_upl_pageinfo
2849 *
2850 * Retrieve the internal page list for the specified upl
2851 *
2852 * Parameters: upl The upl to obtain the page list from
2853 *
2854 * Returns: !NULL The (upl_page_info_t *) for the page
2855 * list internal to the upl
2856 * NULL Error/no page list associated
2857 *
2858 * Notes: IMPORTANT: The function is only valid on internal objects
2859 * where the list request was made with the UPL_INTERNAL flag.
2860 *
2861 * This function is a utility helper function, since some callers
2862 * may not have direct access to the header defining the macro,
2863 * due to abstraction layering constraints.
2864 */
2865 upl_page_info_t *
ubc_upl_pageinfo(upl_t upl)2866 ubc_upl_pageinfo(
2867 upl_t upl)
2868 {
2869 return UPL_GET_INTERNAL_PAGE_LIST(upl);
2870 }
2871
2872
2873 int
UBCINFOEXISTS(const struct vnode * vp)2874 UBCINFOEXISTS(const struct vnode * vp)
2875 {
2876 return (vp) && ((vp)->v_type == VREG) && ((vp)->v_ubcinfo != UBC_INFO_NULL);
2877 }
2878
2879
2880 void
ubc_upl_range_needed(upl_t upl,int index,int count)2881 ubc_upl_range_needed(
2882 upl_t upl,
2883 int index,
2884 int count)
2885 {
2886 upl_range_needed(upl, index, count);
2887 }
2888
2889 boolean_t
ubc_is_mapped(const struct vnode * vp,boolean_t * writable)2890 ubc_is_mapped(const struct vnode *vp, boolean_t *writable)
2891 {
2892 if (!UBCINFOEXISTS(vp) || !ISSET(vp->v_ubcinfo->ui_flags, UI_ISMAPPED)) {
2893 return FALSE;
2894 }
2895 if (writable) {
2896 *writable = ISSET(vp->v_ubcinfo->ui_flags, UI_MAPPEDWRITE);
2897 }
2898 return TRUE;
2899 }
2900
2901 boolean_t
ubc_is_mapped_writable(const struct vnode * vp)2902 ubc_is_mapped_writable(const struct vnode *vp)
2903 {
2904 boolean_t writable;
2905 return ubc_is_mapped(vp, &writable) && writable;
2906 }
2907
2908
2909 /*
2910 * CODE SIGNING
2911 */
2912 static atomic_size_t cs_blob_size = 0;
2913 static atomic_uint_fast32_t cs_blob_count = 0;
2914 static atomic_size_t cs_blob_size_peak = 0;
2915 static atomic_size_t cs_blob_size_max = 0;
2916 static atomic_uint_fast32_t cs_blob_count_peak = 0;
2917
2918 SYSCTL_UINT(_vm, OID_AUTO, cs_blob_count, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_blob_count, 0, "Current number of code signature blobs");
2919 SYSCTL_ULONG(_vm, OID_AUTO, cs_blob_size, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_blob_size, "Current size of all code signature blobs");
2920 SYSCTL_UINT(_vm, OID_AUTO, cs_blob_count_peak, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_blob_count_peak, 0, "Peak number of code signature blobs");
2921 SYSCTL_ULONG(_vm, OID_AUTO, cs_blob_size_peak, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_blob_size_peak, "Peak size of code signature blobs");
2922 SYSCTL_ULONG(_vm, OID_AUTO, cs_blob_size_max, CTLFLAG_RD | CTLFLAG_LOCKED, &cs_blob_size_max, "Size of biggest code signature blob");
2923
2924 /*
2925 * Function: csblob_parse_teamid
2926 *
2927 * Description: This function returns a pointer to the team id
2928 * stored within the codedirectory of the csblob.
2929 * If the codedirectory predates team-ids, it returns
2930 * NULL.
2931 * This does not copy the name but returns a pointer to
2932 * it within the CD. Subsequently, the CD must be
2933 * available when this is used.
2934 */
2935
2936 static const char *
csblob_parse_teamid(struct cs_blob * csblob)2937 csblob_parse_teamid(struct cs_blob *csblob)
2938 {
2939 const CS_CodeDirectory *cd;
2940
2941 cd = csblob->csb_cd;
2942
2943 if (ntohl(cd->version) < CS_SUPPORTSTEAMID) {
2944 return NULL;
2945 }
2946
2947 if (cd->teamOffset == 0) {
2948 return NULL;
2949 }
2950
2951 const char *name = ((const char *)cd) + ntohl(cd->teamOffset);
2952 if (cs_debug > 1) {
2953 printf("found team-id %s in cdblob\n", name);
2954 }
2955
2956 return name;
2957 }
2958
2959
2960 kern_return_t
ubc_cs_blob_allocate(vm_offset_t * blob_addr_p,vm_size_t * blob_size_p)2961 ubc_cs_blob_allocate(
2962 vm_offset_t *blob_addr_p,
2963 vm_size_t *blob_size_p)
2964 {
2965 kern_return_t kr = KERN_FAILURE;
2966 vm_size_t allocation_size = 0;
2967
2968 if (!blob_addr_p || !blob_size_p) {
2969 return KERN_INVALID_ARGUMENT;
2970 }
2971 allocation_size = *blob_size_p;
2972
2973 {
2974 *blob_addr_p = (vm_offset_t) kheap_alloc_tag(KHEAP_DEFAULT,
2975 allocation_size, Z_WAITOK | Z_ZERO, VM_KERN_MEMORY_SECURITY);
2976
2977 if (*blob_addr_p == 0) {
2978 kr = KERN_NO_SPACE;
2979 } else {
2980 kr = KERN_SUCCESS;
2981 }
2982 }
2983
2984 if (kr == KERN_SUCCESS) {
2985 *blob_size_p = allocation_size;
2986 }
2987
2988 return kr;
2989 }
2990
2991 void
ubc_cs_blob_deallocate(vm_offset_t blob_addr,vm_size_t blob_size)2992 ubc_cs_blob_deallocate(
2993 vm_offset_t blob_addr,
2994 vm_size_t blob_size)
2995 {
2996 {
2997 kheap_free(KHEAP_DEFAULT, blob_addr, blob_size);
2998 }
2999 }
3000
3001 /*
3002 * Some codesigned files use a lowest common denominator page size of
3003 * 4KiB, but can be used on systems that have a runtime page size of
3004 * 16KiB. Since faults will only occur on 16KiB ranges in
3005 * cs_validate_range(), we can convert the original Code Directory to
3006 * a multi-level scheme where groups of 4 hashes are combined to form
3007 * a new hash, which represents 16KiB in the on-disk file. This can
3008 * reduce the wired memory requirement for the Code Directory by
3009 * 75%. Care must be taken for binaries that use the "fourk" VM pager
3010 * for unaligned access, which may still attempt to validate on
3011 * non-16KiB multiples for compatibility with 3rd party binaries.
3012 */
3013 static boolean_t
ubc_cs_supports_multilevel_hash(struct cs_blob * blob __unused)3014 ubc_cs_supports_multilevel_hash(struct cs_blob *blob __unused)
3015 {
3016 const CS_CodeDirectory *cd;
3017
3018
3019 /*
3020 * Only applies to binaries that ship as part of the OS,
3021 * primarily the shared cache.
3022 */
3023 if (!blob->csb_platform_binary || blob->csb_teamid != NULL) {
3024 return FALSE;
3025 }
3026
3027 /*
3028 * If the runtime page size matches the code signing page
3029 * size, there is no work to do.
3030 */
3031 if (PAGE_SHIFT <= blob->csb_hash_pageshift) {
3032 return FALSE;
3033 }
3034
3035 cd = blob->csb_cd;
3036
3037 /*
3038 * There must be a valid integral multiple of hashes
3039 */
3040 if (ntohl(cd->nCodeSlots) & (PAGE_MASK >> blob->csb_hash_pageshift)) {
3041 return FALSE;
3042 }
3043
3044 /*
3045 * Scatter lists must also have ranges that have an integral number of hashes
3046 */
3047 if ((ntohl(cd->version) >= CS_SUPPORTSSCATTER) && (ntohl(cd->scatterOffset))) {
3048 const SC_Scatter *scatter = (const SC_Scatter*)
3049 ((const char*)cd + ntohl(cd->scatterOffset));
3050 /* iterate all scatter structs to make sure they are all aligned */
3051 do {
3052 uint32_t sbase = ntohl(scatter->base);
3053 uint32_t scount = ntohl(scatter->count);
3054
3055 /* last scatter? */
3056 if (scount == 0) {
3057 break;
3058 }
3059
3060 if (sbase & (PAGE_MASK >> blob->csb_hash_pageshift)) {
3061 return FALSE;
3062 }
3063
3064 if (scount & (PAGE_MASK >> blob->csb_hash_pageshift)) {
3065 return FALSE;
3066 }
3067
3068 scatter++;
3069 } while (1);
3070 }
3071
3072 /* Covered range must be a multiple of the new page size */
3073 if (ntohl(cd->codeLimit) & PAGE_MASK) {
3074 return FALSE;
3075 }
3076
3077 /* All checks pass */
3078 return TRUE;
3079 }
3080
3081 /*
3082 * Given a validated cs_blob, we reformat the structure to only include
3083 * the blobs which are required by the kernel for our current platform.
3084 * This saves significant memory with agile signatures.
3085 *
3086 * To support rewriting the code directory, potentially through
3087 * multilevel hashes, we provide a mechanism to allocate a code directory
3088 * of a specified size and zero it out --> caller can fill it in.
3089 *
3090 * We don't need to perform a lot of overflow checks as the assumption
3091 * here is that the cs_blob has already been validated.
3092 */
3093 static int
ubc_cs_reconstitute_code_signature(const struct cs_blob * const blob,vm_address_t * const ret_mem_kaddr,vm_size_t * const ret_mem_size,vm_size_t code_directory_size,CS_CodeDirectory ** const code_directory)3094 ubc_cs_reconstitute_code_signature(
3095 const struct cs_blob * const blob,
3096 vm_address_t * const ret_mem_kaddr,
3097 vm_size_t * const ret_mem_size,
3098 vm_size_t code_directory_size,
3099 CS_CodeDirectory ** const code_directory
3100 )
3101 {
3102 vm_address_t new_blob_addr = 0;
3103 vm_size_t new_blob_size = 0;
3104 vm_size_t new_code_directory_size = 0;
3105 const CS_GenericBlob *best_code_directory = NULL;
3106 const CS_GenericBlob *first_code_directory = NULL;
3107 const CS_GenericBlob *der_entitlements_blob = NULL;
3108 const CS_GenericBlob *entitlements_blob = NULL;
3109 const CS_GenericBlob *cms_blob = NULL;
3110 CS_SuperBlob *superblob = NULL;
3111 uint32_t num_blobs = 0;
3112 uint32_t blob_index = 0;
3113 uint32_t blob_offset = 0;
3114 kern_return_t ret;
3115 int err;
3116
3117 if (!blob) {
3118 if (cs_debug > 1) {
3119 printf("CODE SIGNING: CS Blob passed in is NULL\n");
3120 }
3121 return EINVAL;
3122 }
3123
3124 best_code_directory = (const CS_GenericBlob*)blob->csb_cd;
3125 if (!best_code_directory) {
3126 /* This case can never happen, and it is a sign of bad things */
3127 panic("CODE SIGNING: Validated CS Blob has no code directory");
3128 }
3129
3130 new_code_directory_size = code_directory_size;
3131 if (new_code_directory_size == 0) {
3132 new_code_directory_size = ntohl(best_code_directory->length);
3133 }
3134
3135 /*
3136 * A code signature can contain multiple code directories, each of which contains hashes
3137 * of pages based on a hashing algorithm. The kernel selects which hashing algorithm is
3138 * the strongest, and consequently, marks one of these code directories as the best
3139 * matched one. More often than not, the best matched one is _not_ the first one.
3140 *
3141 * However, the CMS blob which cryptographically verifies the code signature is only
3142 * signed against the first code directory. Therefore, if the CMS blob is present, we also
3143 * need the first code directory to be able to verify it. Given this, we organize the
3144 * new cs_blob as following order:
3145 *
3146 * 1. best code directory
3147 * 2. DER encoded entitlements blob (if present)
3148 * 3. entitlements blob (if present)
3149 * 4. cms blob (if present)
3150 * 5. first code directory (if not already the best match, and if cms blob is present)
3151 *
3152 * This order is chosen deliberately, as later on, we expect to get rid of the CMS blob
3153 * and the first code directory once their verification is complete.
3154 */
3155
3156 /* Storage for the super blob header */
3157 new_blob_size += sizeof(CS_SuperBlob);
3158
3159 /* Guaranteed storage for the best code directory */
3160 new_blob_size += sizeof(CS_BlobIndex);
3161 new_blob_size += new_code_directory_size;
3162 num_blobs += 1;
3163
3164 /* Conditional storage for the DER entitlements blob */
3165 der_entitlements_blob = blob->csb_der_entitlements_blob;
3166 if (der_entitlements_blob) {
3167 new_blob_size += sizeof(CS_BlobIndex);
3168 new_blob_size += ntohl(der_entitlements_blob->length);
3169 num_blobs += 1;
3170 }
3171
3172 /* Conditional storage for the entitlements blob */
3173 entitlements_blob = blob->csb_entitlements_blob;
3174 if (entitlements_blob) {
3175 new_blob_size += sizeof(CS_BlobIndex);
3176 new_blob_size += ntohl(entitlements_blob->length);
3177 num_blobs += 1;
3178 }
3179
3180 /* Conditional storage for the CMS blob */
3181 cms_blob = csblob_find_blob_bytes((const uint8_t *)blob->csb_mem_kaddr, blob->csb_mem_size, CSSLOT_SIGNATURESLOT, CSMAGIC_BLOBWRAPPER);
3182 if (cms_blob) {
3183 new_blob_size += sizeof(CS_BlobIndex);
3184 new_blob_size += ntohl(cms_blob->length);
3185 num_blobs += 1;
3186 }
3187
3188 /*
3189 * Conditional storage for the first code directory.
3190 * This is only needed if a CMS blob exists and the best code directory isn't already
3191 * the first one. It is an error if we find a CMS blob but do not find a first code directory.
3192 */
3193 if (cms_blob) {
3194 first_code_directory = csblob_find_blob_bytes((const uint8_t *)blob->csb_mem_kaddr, blob->csb_mem_size, CSSLOT_CODEDIRECTORY, CSMAGIC_CODEDIRECTORY);
3195 if (first_code_directory == best_code_directory) {
3196 /* We don't need the first code directory anymore, since the best one is already it */
3197 first_code_directory = NULL;
3198 } else if (first_code_directory) {
3199 new_blob_size += sizeof(CS_BlobIndex);
3200 new_blob_size += ntohl(first_code_directory->length);
3201 num_blobs += 1;
3202 } else {
3203 printf("CODE SIGNING: Invalid CS Blob: found CMS blob but not a first code directory\n");
3204 return EINVAL;
3205 }
3206 }
3207
3208 /*
3209 * The blob size could be rouded up to page size here, so we keep a copy
3210 * of the actual superblob length as well.
3211 */
3212 vm_size_t new_blob_allocation_size = new_blob_size;
3213 ret = ubc_cs_blob_allocate(&new_blob_addr, &new_blob_allocation_size);
3214 if (ret != KERN_SUCCESS) {
3215 printf("CODE SIGNING: Failed to allocate memory for new code signing blob: %d\n", ret);
3216 return ENOMEM;
3217 }
3218
3219 /*
3220 * Fill out the superblob header and then all the blobs in the order listed
3221 * above.
3222 */
3223 superblob = (CS_SuperBlob*)new_blob_addr;
3224 superblob->magic = htonl(CSMAGIC_EMBEDDED_SIGNATURE);
3225 superblob->length = htonl((uint32_t)new_blob_size);
3226 superblob->count = htonl(num_blobs);
3227
3228 blob_index = 0;
3229 blob_offset = sizeof(CS_SuperBlob) + (num_blobs * sizeof(CS_BlobIndex));
3230
3231 /* Best code directory */
3232 superblob->index[blob_index].offset = htonl(blob_offset);
3233 if (first_code_directory) {
3234 superblob->index[blob_index].type = htonl(CSSLOT_ALTERNATE_CODEDIRECTORIES);
3235 } else {
3236 superblob->index[blob_index].type = htonl(CSSLOT_CODEDIRECTORY);
3237 }
3238
3239 if (code_directory_size > 0) {
3240 /* We zero out the code directory, as we expect the caller to fill it in */
3241 memset((void*)(new_blob_addr + blob_offset), 0, new_code_directory_size);
3242 } else {
3243 memcpy((void*)(new_blob_addr + blob_offset), best_code_directory, new_code_directory_size);
3244 }
3245
3246 if (code_directory) {
3247 *code_directory = (CS_CodeDirectory*)(new_blob_addr + blob_offset);
3248 }
3249 blob_offset += new_code_directory_size;
3250
3251 /* DER entitlements blob */
3252 if (der_entitlements_blob) {
3253 blob_index += 1;
3254 superblob->index[blob_index].offset = htonl(blob_offset);
3255 superblob->index[blob_index].type = htonl(CSSLOT_DER_ENTITLEMENTS);
3256
3257 memcpy((void*)(new_blob_addr + blob_offset), der_entitlements_blob, ntohl(der_entitlements_blob->length));
3258 blob_offset += ntohl(der_entitlements_blob->length);
3259 }
3260
3261 /* Entitlements blob */
3262 if (entitlements_blob) {
3263 blob_index += 1;
3264 superblob->index[blob_index].offset = htonl(blob_offset);
3265 superblob->index[blob_index].type = htonl(CSSLOT_ENTITLEMENTS);
3266
3267 memcpy((void*)(new_blob_addr + blob_offset), entitlements_blob, ntohl(entitlements_blob->length));
3268 blob_offset += ntohl(entitlements_blob->length);
3269 }
3270
3271 /* CMS blob */
3272 if (cms_blob) {
3273 blob_index += 1;
3274 superblob->index[blob_index].offset = htonl(blob_offset);
3275 superblob->index[blob_index].type = htonl(CSSLOT_SIGNATURESLOT);
3276 memcpy((void*)(new_blob_addr + blob_offset), cms_blob, ntohl(cms_blob->length));
3277 blob_offset += ntohl(cms_blob->length);
3278 }
3279
3280 /* First code directory */
3281 if (first_code_directory) {
3282 blob_index += 1;
3283 superblob->index[blob_index].offset = htonl(blob_offset);
3284 superblob->index[blob_index].type = htonl(CSSLOT_CODEDIRECTORY);
3285 memcpy((void*)(new_blob_addr + blob_offset), first_code_directory, ntohl(first_code_directory->length));
3286 blob_offset += ntohl(first_code_directory->length);
3287 }
3288
3289 /*
3290 * We only validate the blob in case we copied in the best code directory.
3291 * In case the code directory size we were passed in wasn't 0, we memset the best
3292 * code directory to 0 and expect the caller to fill it in. In the same spirit, we
3293 * expect the caller to validate the code signature after they fill in the code
3294 * directory.
3295 */
3296 if (code_directory_size == 0) {
3297 const CS_CodeDirectory *validated_code_directory = NULL;
3298 const CS_GenericBlob *validated_entitlements_blob = NULL;
3299 const CS_GenericBlob *validated_der_entitlements_blob = NULL;
3300 ret = cs_validate_csblob((const uint8_t *)superblob, new_blob_size, &validated_code_directory, &validated_entitlements_blob, &validated_der_entitlements_blob);
3301 if (ret) {
3302 printf("CODE SIGNING: Validation of reconstituted blob failed: %d\n", ret);
3303 err = EINVAL;
3304 goto fail;
3305 }
3306 }
3307
3308 if (ret_mem_kaddr) {
3309 *ret_mem_kaddr = new_blob_addr;
3310 }
3311 if (ret_mem_size) {
3312 *ret_mem_size = new_blob_allocation_size;
3313 }
3314
3315 return 0;
3316
3317 fail:
3318 ubc_cs_blob_deallocate(new_blob_addr, new_blob_allocation_size);
3319 return err;
3320 }
3321
3322 #if CONFIG_ENFORCE_SIGNED_CODE
3323 /*
3324 * We use this function to clear out unnecessary bits from the code signature
3325 * blob which are no longer needed. We free these bits and give them back to
3326 * the kernel. This is needed since reconstitution includes extra data which is
3327 * needed only for verification but has no point in keeping afterwards.
3328 *
3329 * This results in significant memory reduction, especially for 3rd party apps
3330 * since we also get rid of the CMS blob.
3331 */
3332 static int
ubc_cs_clear_unneeded_code_signature(struct cs_blob * blob)3333 ubc_cs_clear_unneeded_code_signature(
3334 struct cs_blob *blob
3335 )
3336 {
3337 CS_SuperBlob *superblob = NULL;
3338 uint32_t num_blobs = 0;
3339 vm_size_t last_needed_blob_offset = 0;
3340 kern_return_t ret = KERN_FAILURE;
3341 bool kmem_allocated = false;
3342
3343 /*
3344 * The only blobs we need to keep are the code directory and the entitlements
3345 * blob. These should have a certain ordering to them if we know that the
3346 * blob has been reconstituted in the past.
3347 *
3348 * Ordering:
3349 * 1. Code directory
3350 * 2. DER encoded entitlements (if present)
3351 *
3352 * We need to clear out the remaining page after these blobs end, and fix up
3353 * the superblob for the changes. Things gets a little more complicated for
3354 * blobs which may not have been kmem_allocated. For those, we simply just
3355 * allocate the new required space and copy into it.
3356 */
3357
3358 if (!blob) {
3359 if (cs_debug > 1) {
3360 printf("CODE SIGNING: CS Blob passed in is NULL\n");
3361 }
3362 return EINVAL;
3363 }
3364
3365 if (!blob->csb_reconstituted) {
3366 /*
3367 * Nothing for us to do, since we can't make any claims about how this
3368 * blob may have been ordered.
3369 */
3370 return 0;
3371 }
3372
3373
3374 if (!blob->csb_cd) {
3375 /* This case can never happen, and it is a sign of bad things */
3376 panic("CODE SIGNING: Validated CS Blob has no code directory");
3377 }
3378 superblob = (CS_SuperBlob*)blob->csb_mem_kaddr;
3379
3380 num_blobs = 1;
3381 last_needed_blob_offset = ntohl(superblob->index[0].offset) + ntohl(blob->csb_cd->length);
3382
3383 /* Check for DER entitlements */
3384 if (blob->csb_der_entitlements_blob) {
3385 num_blobs += 1;
3386 last_needed_blob_offset += ntohl(blob->csb_der_entitlements_blob->length);
3387 }
3388
3389 superblob->count = htonl(num_blobs);
3390 superblob->length = htonl((uint32_t)last_needed_blob_offset);
3391
3392 /*
3393 * There is a chance that the code directory is marked within the superblob as an
3394 * alternate code directory. This happens when the first code directory isn't the
3395 * best one chosen by the kernel, so to be able to access both the first and the best,
3396 * we save the best one as an alternate one. Since we're getting rid of the first one
3397 * here, we mark the best one as the first one.
3398 */
3399 superblob->index[0].type = htonl(CSSLOT_CODEDIRECTORY);
3400
3401 /*
3402 * If we are kmem_allocated, then we can free all the remaining pages which we no longer
3403 * need. However, this cannot be done if we didn't allocate page-wise, but byte-wise through
3404 * something like kalloc. In the latter case, we just allocate the required space again, and
3405 * copy over only the required portion of the superblob.
3406 */
3407 if (kmem_allocated) {
3408 vm_size_t last_needed_page_offset = round_page(last_needed_blob_offset);
3409 assert(last_needed_page_offset <= blob->csb_mem_size);
3410
3411 vm_address_t unneeded_blob_addr = (vm_address_t)blob->csb_mem_kaddr + last_needed_page_offset;
3412 vm_size_t unneeded_blob_size = blob->csb_mem_size - last_needed_page_offset;
3413
3414 /* These both need to be page aligned */
3415 assert((unneeded_blob_addr & PAGE_MASK) == 0);
3416 assert((unneeded_blob_size & PAGE_MASK) == 0);
3417
3418 /* Free the unneeded memory */
3419 if (unneeded_blob_addr && unneeded_blob_size) {
3420 kmem_free(kernel_map, unneeded_blob_addr, unneeded_blob_size);
3421 }
3422
3423 /* Zero out the remaining bytes in the same page */
3424 vm_size_t unneeded_bytes_in_page = last_needed_page_offset - last_needed_blob_offset;
3425 memset((uint8_t*)superblob + last_needed_blob_offset, 0, unneeded_bytes_in_page);
3426 blob->csb_mem_size = last_needed_page_offset;
3427 } else {
3428 vm_address_t new_superblob = 0;
3429 vm_size_t new_superblob_size = last_needed_blob_offset;
3430
3431 ret = ubc_cs_blob_allocate(&new_superblob, &new_superblob_size);
3432 if (ret != KERN_SUCCESS) {
3433 printf("CODE SIGNING: Unable to allocate space when trying to clear unneeded code signature blobs: %d\n", ret);
3434 return ENOMEM;
3435 }
3436
3437 /*
3438 * As we weren't kmem_allocated before, we will not be kmem_allocated again. This should
3439 * mean the size we passed in is exactly the size we should get back for the allocation.
3440 */
3441 assert(new_superblob_size == last_needed_blob_offset);
3442
3443 /* Copy in the updated superblob into the new memory */
3444 memcpy((void*)new_superblob, superblob, new_superblob_size);
3445
3446 /* Free the old code signature and old memory */
3447 ubc_cs_blob_deallocate((vm_offset_t)blob->csb_mem_kaddr, blob->csb_mem_size);
3448
3449 /* Setup the code signature blob again */
3450 blob->csb_mem_kaddr = (void *)new_superblob;
3451 blob->csb_mem_size = new_superblob_size;
3452 blob->csb_cd = (const CS_CodeDirectory*)csblob_find_blob_bytes((uint8_t*)new_superblob, new_superblob_size, CSSLOT_CODEDIRECTORY, CSMAGIC_CODEDIRECTORY);
3453
3454 blob->csb_der_entitlements_blob = csblob_find_blob_bytes((uint8_t*)new_superblob, new_superblob_size, CSSLOT_DER_ENTITLEMENTS, CSMAGIC_EMBEDDED_DER_ENTITLEMENTS);
3455 }
3456
3457 blob->csb_entitlements_blob = NULL;
3458
3459 const CS_CodeDirectory *validated_code_directory = NULL;
3460 const CS_GenericBlob *validated_entitlements_blob = NULL;
3461 const CS_GenericBlob *validated_der_entitlements_blob = NULL;
3462 ret = cs_validate_csblob((const uint8_t *)blob->csb_mem_kaddr, blob->csb_mem_size, &validated_code_directory, &validated_entitlements_blob, &validated_der_entitlements_blob);
3463 if (ret) {
3464 printf("CODE SIGNING: Validation of blob after clearing unneeded code signature blobs failed: %d\n", ret);
3465 return EINVAL;
3466 }
3467
3468 return 0;
3469 }
3470 #endif /* CONFIG_ENFORCE_SIGNED_CODE */
3471
3472 static int
ubc_cs_convert_to_multilevel_hash(struct cs_blob * blob)3473 ubc_cs_convert_to_multilevel_hash(struct cs_blob *blob)
3474 {
3475 const CS_CodeDirectory *old_cd, *cd;
3476 CS_CodeDirectory *new_cd;
3477 const CS_GenericBlob *entitlements;
3478 const CS_GenericBlob *der_entitlements;
3479 vm_offset_t new_blob_addr;
3480 vm_size_t new_blob_size;
3481 vm_size_t new_cdsize;
3482 int error;
3483
3484 uint32_t hashes_per_new_hash_shift = (uint32_t)(PAGE_SHIFT - blob->csb_hash_pageshift);
3485
3486 if (cs_debug > 1) {
3487 printf("CODE SIGNING: Attempting to convert Code Directory for %lu -> %lu page shift\n",
3488 (unsigned long)blob->csb_hash_pageshift, (unsigned long)PAGE_SHIFT);
3489 }
3490
3491 old_cd = blob->csb_cd;
3492
3493 /* Up to the hashes, we can copy all data */
3494 new_cdsize = ntohl(old_cd->hashOffset);
3495 new_cdsize += (ntohl(old_cd->nCodeSlots) >> hashes_per_new_hash_shift) * old_cd->hashSize;
3496
3497 error = ubc_cs_reconstitute_code_signature(blob, &new_blob_addr, &new_blob_size, new_cdsize, &new_cd);
3498 if (error != 0) {
3499 printf("CODE SIGNING: Failed to reconsitute code signature: %d\n", error);
3500 return error;
3501 }
3502 entitlements = csblob_find_blob_bytes((uint8_t*)new_blob_addr, new_blob_size, CSSLOT_ENTITLEMENTS, CSMAGIC_EMBEDDED_ENTITLEMENTS);
3503 der_entitlements = csblob_find_blob_bytes((uint8_t*)new_blob_addr, new_blob_size, CSSLOT_DER_ENTITLEMENTS, CSMAGIC_EMBEDDED_DER_ENTITLEMENTS);
3504
3505 memcpy(new_cd, old_cd, ntohl(old_cd->hashOffset));
3506
3507 /* Update fields in the Code Directory structure */
3508 new_cd->length = htonl((uint32_t)new_cdsize);
3509
3510 uint32_t nCodeSlots = ntohl(new_cd->nCodeSlots);
3511 nCodeSlots >>= hashes_per_new_hash_shift;
3512 new_cd->nCodeSlots = htonl(nCodeSlots);
3513
3514 new_cd->pageSize = (uint8_t)PAGE_SHIFT; /* Not byte-swapped */
3515
3516 if ((ntohl(new_cd->version) >= CS_SUPPORTSSCATTER) && (ntohl(new_cd->scatterOffset))) {
3517 SC_Scatter *scatter = (SC_Scatter*)
3518 ((char *)new_cd + ntohl(new_cd->scatterOffset));
3519 /* iterate all scatter structs to scale their counts */
3520 do {
3521 uint32_t scount = ntohl(scatter->count);
3522 uint32_t sbase = ntohl(scatter->base);
3523
3524 /* last scatter? */
3525 if (scount == 0) {
3526 break;
3527 }
3528
3529 scount >>= hashes_per_new_hash_shift;
3530 scatter->count = htonl(scount);
3531
3532 sbase >>= hashes_per_new_hash_shift;
3533 scatter->base = htonl(sbase);
3534
3535 scatter++;
3536 } while (1);
3537 }
3538
3539 /* For each group of hashes, hash them together */
3540 const unsigned char *src_base = (const unsigned char *)old_cd + ntohl(old_cd->hashOffset);
3541 unsigned char *dst_base = (unsigned char *)new_cd + ntohl(new_cd->hashOffset);
3542
3543 uint32_t hash_index;
3544 for (hash_index = 0; hash_index < nCodeSlots; hash_index++) {
3545 union cs_hash_union mdctx;
3546
3547 uint32_t source_hash_len = old_cd->hashSize << hashes_per_new_hash_shift;
3548 const unsigned char *src = src_base + hash_index * source_hash_len;
3549 unsigned char *dst = dst_base + hash_index * new_cd->hashSize;
3550
3551 blob->csb_hashtype->cs_init(&mdctx);
3552 blob->csb_hashtype->cs_update(&mdctx, src, source_hash_len);
3553 blob->csb_hashtype->cs_final(dst, &mdctx);
3554 }
3555
3556 error = cs_validate_csblob((const uint8_t *)new_blob_addr, new_blob_size, &cd, &entitlements, &der_entitlements);
3557 if (error != 0) {
3558 printf("CODE SIGNING: Failed to validate new Code Signing Blob: %d\n",
3559 error);
3560
3561 ubc_cs_blob_deallocate(new_blob_addr, new_blob_size);
3562 return error;
3563 }
3564
3565 /* New Code Directory is ready for use, swap it out in the blob structure */
3566 ubc_cs_blob_deallocate((vm_offset_t)blob->csb_mem_kaddr, blob->csb_mem_size);
3567
3568 blob->csb_mem_size = new_blob_size;
3569 blob->csb_mem_kaddr = (void *)new_blob_addr;
3570 blob->csb_cd = cd;
3571 blob->csb_entitlements_blob = NULL;
3572
3573 blob->csb_der_entitlements_blob = der_entitlements; /* may be NULL, not yet validated */
3574 blob->csb_reconstituted = true;
3575
3576 /* The blob has some cached attributes of the Code Directory, so update those */
3577
3578 blob->csb_hash_firstlevel_pageshift = blob->csb_hash_pageshift; /* Save the original page size */
3579
3580 blob->csb_hash_pageshift = PAGE_SHIFT;
3581 blob->csb_end_offset = ntohl(cd->codeLimit);
3582 if ((ntohl(cd->version) >= CS_SUPPORTSSCATTER) && (ntohl(cd->scatterOffset))) {
3583 const SC_Scatter *scatter = (const SC_Scatter*)
3584 ((const char*)cd + ntohl(cd->scatterOffset));
3585 blob->csb_start_offset = ((off_t)ntohl(scatter->base)) * PAGE_SIZE;
3586 } else {
3587 blob->csb_start_offset = 0;
3588 }
3589
3590 return 0;
3591 }
3592
3593 static void
cs_blob_cleanup(struct cs_blob * blob)3594 cs_blob_cleanup(struct cs_blob *blob)
3595 {
3596 if (blob->profile_kaddr) {
3597 kmem_free(kernel_map, blob->profile_kaddr, blob->profile_allocation_size);
3598 }
3599 blob->profile_kaddr = 0;
3600 blob->profile_allocation_size = 0;
3601
3602 if (blob->csb_mem_kaddr) {
3603 ubc_cs_blob_deallocate((vm_offset_t)blob->csb_mem_kaddr, blob->csb_mem_size);
3604 }
3605 blob->csb_mem_kaddr = NULL;
3606 blob->csb_mem_size = 0;
3607
3608 if (blob->csb_entitlements != NULL) {
3609 if (amfi) {
3610 // TODO: PANIC if amfi isn't present
3611 amfi->OSEntitlements_invalidate(blob->csb_entitlements);
3612 }
3613 osobject_release(blob->csb_entitlements);
3614 blob->csb_entitlements = NULL;
3615 }
3616 }
3617
3618 static void
cs_blob_ro_free(struct cs_blob * blob)3619 cs_blob_ro_free(struct cs_blob *blob)
3620 {
3621 struct cs_blob tmp;
3622
3623 if (blob != NULL) {
3624 /*
3625 * cs_blob_cleanup clears fields, so we need to pass it a
3626 * mutable copy.
3627 */
3628 tmp = *blob;
3629 cs_blob_cleanup(&tmp);
3630
3631 zfree_ro(ZONE_ID_CS_BLOB, blob);
3632 }
3633 }
3634
3635 /*
3636 * Free a cs_blob previously created by cs_blob_create_validated.
3637 */
3638 void
cs_blob_free(struct cs_blob * blob)3639 cs_blob_free(
3640 struct cs_blob *blob)
3641 {
3642 cs_blob_ro_free(blob);
3643 }
3644
3645 static int
cs_blob_init_validated(vm_address_t * const addr,vm_size_t size,struct cs_blob * blob,CS_CodeDirectory const ** const ret_cd)3646 cs_blob_init_validated(
3647 vm_address_t * const addr,
3648 vm_size_t size,
3649 struct cs_blob *blob,
3650 CS_CodeDirectory const ** const ret_cd)
3651 {
3652 int error = EINVAL;
3653 const CS_CodeDirectory *cd = NULL;
3654 const CS_GenericBlob *entitlements = NULL;
3655 const CS_GenericBlob *der_entitlements = NULL;
3656 union cs_hash_union mdctx;
3657 size_t length;
3658
3659 bzero(blob, sizeof(*blob));
3660
3661 /* fill in the new blob */
3662 blob->csb_mem_size = size;
3663 blob->csb_mem_offset = 0;
3664 blob->csb_mem_kaddr = (void *)*addr;
3665 blob->csb_flags = 0;
3666 blob->csb_signer_type = CS_SIGNER_TYPE_UNKNOWN;
3667 blob->csb_platform_binary = 0;
3668 blob->csb_platform_path = 0;
3669 blob->csb_teamid = NULL;
3670 #if CONFIG_SUPPLEMENTAL_SIGNATURES
3671 blob->csb_supplement_teamid = NULL;
3672 #endif
3673 blob->csb_entitlements_blob = NULL;
3674 blob->csb_der_entitlements_blob = NULL;
3675 blob->csb_entitlements = NULL;
3676 blob->csb_reconstituted = false;
3677 blob->profile_kaddr = 0;
3678 blob->profile_allocation_size = 0;
3679
3680 /* Transfer ownership. Even on error, this function will deallocate */
3681 *addr = 0;
3682
3683 /*
3684 * Validate the blob's contents
3685 */
3686 length = (size_t) size;
3687 error = cs_validate_csblob((const uint8_t *)blob->csb_mem_kaddr,
3688 length, &cd, &entitlements, &der_entitlements);
3689 if (error) {
3690 if (cs_debug) {
3691 printf("CODESIGNING: csblob invalid: %d\n", error);
3692 }
3693 /*
3694 * The vnode checker can't make the rest of this function
3695 * succeed if csblob validation failed, so bail */
3696 goto out;
3697 } else {
3698 const unsigned char *md_base;
3699 uint8_t hash[CS_HASH_MAX_SIZE];
3700 int md_size;
3701 vm_offset_t hash_pagemask;
3702
3703 blob->csb_cd = cd;
3704 blob->csb_entitlements_blob = entitlements; /* may be NULL, not yet validated */
3705 blob->csb_der_entitlements_blob = der_entitlements; /* may be NULL, not yet validated */
3706 blob->csb_hashtype = cs_find_md(cd->hashType);
3707 if (blob->csb_hashtype == NULL || blob->csb_hashtype->cs_digest_size > sizeof(hash)) {
3708 panic("validated CodeDirectory but unsupported type");
3709 }
3710
3711 blob->csb_hash_pageshift = cd->pageSize;
3712 hash_pagemask = (1U << cd->pageSize) - 1;
3713 blob->csb_hash_firstlevel_pageshift = 0;
3714 blob->csb_flags = (ntohl(cd->flags) & CS_ALLOWED_MACHO) | CS_VALID;
3715 blob->csb_end_offset = (((vm_offset_t)ntohl(cd->codeLimit) + hash_pagemask) & ~hash_pagemask);
3716 if ((ntohl(cd->version) >= CS_SUPPORTSSCATTER) && (ntohl(cd->scatterOffset))) {
3717 const SC_Scatter *scatter = (const SC_Scatter*)
3718 ((const char*)cd + ntohl(cd->scatterOffset));
3719 blob->csb_start_offset = ((off_t)ntohl(scatter->base)) * (1U << blob->csb_hash_pageshift);
3720 } else {
3721 blob->csb_start_offset = 0;
3722 }
3723 /* compute the blob's cdhash */
3724 md_base = (const unsigned char *) cd;
3725 md_size = ntohl(cd->length);
3726
3727 blob->csb_hashtype->cs_init(&mdctx);
3728 blob->csb_hashtype->cs_update(&mdctx, md_base, md_size);
3729 blob->csb_hashtype->cs_final(hash, &mdctx);
3730
3731 memcpy(blob->csb_cdhash, hash, CS_CDHASH_LEN);
3732
3733 #if CONFIG_SUPPLEMENTAL_SIGNATURES
3734 blob->csb_linkage_hashtype = NULL;
3735 if (ntohl(cd->version) >= CS_SUPPORTSLINKAGE && cd->linkageHashType != 0 &&
3736 ntohl(cd->linkageSize) >= CS_CDHASH_LEN) {
3737 blob->csb_linkage_hashtype = cs_find_md(cd->linkageHashType);
3738
3739 if (blob->csb_linkage_hashtype != NULL) {
3740 memcpy(blob->csb_linkage, (uint8_t const*)cd + ntohl(cd->linkageOffset),
3741 CS_CDHASH_LEN);
3742 }
3743 }
3744 #endif
3745 }
3746
3747 error = 0;
3748
3749 out:
3750 if (error != 0) {
3751 cs_blob_cleanup(blob);
3752 blob = NULL;
3753 cd = NULL;
3754 }
3755
3756 if (ret_cd != NULL) {
3757 *ret_cd = cd;
3758 }
3759
3760 return error;
3761 }
3762
3763 /*
3764 * Validate the code signature blob, create a struct cs_blob wrapper
3765 * and return it together with a pointer to the chosen code directory
3766 * and entitlements blob.
3767 *
3768 * Note that this takes ownership of the memory as addr, mainly because
3769 * this function can actually replace the passed in blob with another
3770 * one, e.g. when performing multilevel hashing optimization.
3771 */
3772 int
cs_blob_create_validated(vm_address_t * const addr,vm_size_t size,struct cs_blob ** const ret_blob,CS_CodeDirectory const ** const ret_cd)3773 cs_blob_create_validated(
3774 vm_address_t * const addr,
3775 vm_size_t size,
3776 struct cs_blob ** const ret_blob,
3777 CS_CodeDirectory const ** const ret_cd)
3778 {
3779 struct cs_blob blob = {};
3780 struct cs_blob *ro_blob;
3781 int error;
3782
3783 if (ret_blob) {
3784 *ret_blob = NULL;
3785 }
3786
3787 if ((error = cs_blob_init_validated(addr, size, &blob, ret_cd)) != 0) {
3788 return error;
3789 }
3790
3791 if (ret_blob != NULL) {
3792 ro_blob = zalloc_ro(ZONE_ID_CS_BLOB, Z_WAITOK | Z_NOFAIL);
3793 zalloc_ro_update_elem(ZONE_ID_CS_BLOB, ro_blob, &blob);
3794 *ret_blob = ro_blob;
3795 }
3796
3797 return error;
3798 }
3799
3800 #if CONFIG_SUPPLEMENTAL_SIGNATURES
3801 static void
cs_blob_supplement_free(struct cs_blob * const blob)3802 cs_blob_supplement_free(struct cs_blob * const blob)
3803 {
3804 void *teamid;
3805
3806 if (blob != NULL) {
3807 if (blob->csb_supplement_teamid != NULL) {
3808 teamid = blob->csb_supplement_teamid;
3809 vm_size_t teamid_size = strlen(blob->csb_supplement_teamid) + 1;
3810 kfree_data(teamid, teamid_size);
3811 }
3812 cs_blob_ro_free(blob);
3813 }
3814 }
3815 #endif
3816
3817 static void
ubc_cs_blob_adjust_statistics(struct cs_blob const * blob)3818 ubc_cs_blob_adjust_statistics(struct cs_blob const *blob)
3819 {
3820 /* Note that the atomic ops are not enough to guarantee
3821 * correctness: If a blob with an intermediate size is inserted
3822 * concurrently, we can lose a peak value assignment. But these
3823 * statistics are only advisory anyway, so we're not going to
3824 * employ full locking here. (Consequently, we are also okay with
3825 * relaxed ordering of those accesses.)
3826 */
3827
3828 unsigned int new_cs_blob_count = os_atomic_add(&cs_blob_count, 1, relaxed);
3829 if (new_cs_blob_count > os_atomic_load(&cs_blob_count_peak, relaxed)) {
3830 os_atomic_store(&cs_blob_count_peak, new_cs_blob_count, relaxed);
3831 }
3832
3833 size_t new_cs_blob_size = os_atomic_add(&cs_blob_size, blob->csb_mem_size, relaxed);
3834
3835 if (new_cs_blob_size > os_atomic_load(&cs_blob_size_peak, relaxed)) {
3836 os_atomic_store(&cs_blob_size_peak, new_cs_blob_size, relaxed);
3837 }
3838 if (blob->csb_mem_size > os_atomic_load(&cs_blob_size_max, relaxed)) {
3839 os_atomic_store(&cs_blob_size_max, blob->csb_mem_size, relaxed);
3840 }
3841 }
3842
3843 static void
cs_blob_set_cpu_type(struct cs_blob * blob,cpu_type_t cputype)3844 cs_blob_set_cpu_type(struct cs_blob *blob, cpu_type_t cputype)
3845 {
3846 zalloc_ro_update_field(ZONE_ID_CS_BLOB, blob, csb_cpu_type, &cputype);
3847 }
3848
3849 __abortlike
3850 static void
panic_cs_blob_backref_mismatch(struct cs_blob * blob,struct vnode * vp)3851 panic_cs_blob_backref_mismatch(struct cs_blob *blob, struct vnode *vp)
3852 {
3853 panic("cs_blob vnode backref mismatch: blob=%p, vp=%p, "
3854 "blob->csb_vnode=%p", blob, vp, blob->csb_vnode);
3855 }
3856
3857 void
cs_blob_require(struct cs_blob * blob,vnode_t vp)3858 cs_blob_require(struct cs_blob *blob, vnode_t vp)
3859 {
3860 zone_require_ro(ZONE_ID_CS_BLOB, sizeof(struct cs_blob), blob);
3861
3862 if (vp != NULL && __improbable(blob->csb_vnode != vp)) {
3863 panic_cs_blob_backref_mismatch(blob, vp);
3864 }
3865 }
3866
3867 int
ubc_cs_blob_add(struct vnode * vp,uint32_t platform,cpu_type_t cputype,cpu_subtype_t cpusubtype,off_t base_offset,vm_address_t * addr,vm_size_t size,struct image_params * imgp,__unused int flags,struct cs_blob ** ret_blob)3868 ubc_cs_blob_add(
3869 struct vnode *vp,
3870 uint32_t platform,
3871 cpu_type_t cputype,
3872 cpu_subtype_t cpusubtype,
3873 off_t base_offset,
3874 vm_address_t *addr,
3875 vm_size_t size,
3876 struct image_params *imgp,
3877 __unused int flags,
3878 struct cs_blob **ret_blob)
3879 {
3880 kern_return_t kr;
3881 struct ubc_info *uip;
3882 struct cs_blob tmp_blob;
3883 struct cs_blob *blob_ro = NULL;
3884 struct cs_blob *oblob;
3885 int error;
3886 CS_CodeDirectory const *cd;
3887 off_t blob_start_offset, blob_end_offset;
3888 boolean_t record_mtime;
3889
3890 record_mtime = FALSE;
3891 if (ret_blob) {
3892 *ret_blob = NULL;
3893 }
3894
3895 /* Create the struct cs_blob wrapper that will be attached to the vnode.
3896 * Validates the passed in blob in the process. */
3897 error = cs_blob_init_validated(addr, size, &tmp_blob, &cd);
3898
3899 if (error != 0) {
3900 printf("malform code signature blob: %d\n", error);
3901 return error;
3902 }
3903
3904 tmp_blob.csb_cpu_type = cputype;
3905 tmp_blob.csb_cpu_subtype = cpusubtype & ~CPU_SUBTYPE_MASK;
3906 tmp_blob.csb_base_offset = base_offset;
3907
3908 #if CONFIG_ENFORCE_SIGNED_CODE
3909 /*
3910 * Reconstitute code signature
3911 */
3912 {
3913 vm_address_t new_mem_kaddr = 0;
3914 vm_size_t new_mem_size = 0;
3915
3916 CS_CodeDirectory *new_cd = NULL;
3917 const CS_GenericBlob *new_entitlements = NULL;
3918 const CS_GenericBlob *new_der_entitlements = NULL;
3919
3920 error = ubc_cs_reconstitute_code_signature(&tmp_blob, &new_mem_kaddr, &new_mem_size, 0, &new_cd);
3921 if (error != 0) {
3922 printf("failed code signature reconstitution: %d\n", error);
3923 goto out;
3924 }
3925 new_entitlements = csblob_find_blob_bytes((uint8_t*)new_mem_kaddr, new_mem_size, CSSLOT_ENTITLEMENTS, CSMAGIC_EMBEDDED_ENTITLEMENTS);
3926 new_der_entitlements = csblob_find_blob_bytes((uint8_t*)new_mem_kaddr, new_mem_size, CSSLOT_DER_ENTITLEMENTS, CSMAGIC_EMBEDDED_DER_ENTITLEMENTS);
3927
3928 ubc_cs_blob_deallocate((vm_offset_t)tmp_blob.csb_mem_kaddr, tmp_blob.csb_mem_size);
3929
3930 tmp_blob.csb_mem_kaddr = (void *)new_mem_kaddr;
3931 tmp_blob.csb_mem_size = new_mem_size;
3932 tmp_blob.csb_cd = new_cd;
3933 tmp_blob.csb_entitlements_blob = new_entitlements;
3934 tmp_blob.csb_der_entitlements_blob = new_der_entitlements;
3935 tmp_blob.csb_reconstituted = true;
3936 }
3937 #endif
3938
3939
3940 blob_ro = zalloc_ro(ZONE_ID_CS_BLOB, Z_WAITOK | Z_NOFAIL);
3941 tmp_blob.csb_ro_addr = blob_ro;
3942 tmp_blob.csb_vnode = vp;
3943
3944 /* AMFI needs to see the current blob state at the RO address. */
3945 zalloc_ro_update_elem(ZONE_ID_CS_BLOB, blob_ro, &tmp_blob);
3946
3947 #if CONFIG_MACF
3948 /*
3949 * Let policy module check whether the blob's signature is accepted.
3950 */
3951
3952 unsigned int cs_flags = tmp_blob.csb_flags;
3953 unsigned int signer_type = tmp_blob.csb_signer_type;
3954 error = mac_vnode_check_signature(vp, &tmp_blob, imgp, &cs_flags, &signer_type, flags, platform);
3955
3956 tmp_blob.csb_flags = cs_flags;
3957 tmp_blob.csb_signer_type = signer_type;
3958
3959 if (error) {
3960 if (cs_debug) {
3961 printf("check_signature[pid: %d], error = %d\n", proc_getpid(current_proc()), error);
3962 }
3963 goto out;
3964 }
3965 if ((flags & MAC_VNODE_CHECK_DYLD_SIM) && !(tmp_blob.csb_flags & CS_PLATFORM_BINARY)) {
3966 if (cs_debug) {
3967 printf("check_signature[pid: %d], is not apple signed\n", proc_getpid(current_proc()));
3968 }
3969 error = EPERM;
3970 goto out;
3971 }
3972 #endif
3973
3974
3975 #if CONFIG_ENFORCE_SIGNED_CODE
3976 /*
3977 * When this flag is turned on, we reconstitue the code signature to only
3978 * include the blobs which are needed. This may include the first code
3979 * directory and the CMS blob. However, now that verification of this blob
3980 * is complete, we don't need all these blobs. Hence, we clear them out.
3981 */
3982
3983 if (ubc_cs_clear_unneeded_code_signature(&tmp_blob)) {
3984 error = EPERM;
3985 goto out;
3986 }
3987 #endif /* CONFIG_ENFORCE_SIGNED_CODE */
3988
3989 tmp_blob.csb_entitlements_blob = NULL;
3990
3991
3992 if (tmp_blob.csb_flags & CS_PLATFORM_BINARY) {
3993 if (cs_debug > 1) {
3994 printf("check_signature[pid: %d]: platform binary\n", proc_getpid(current_proc()));
3995 }
3996 tmp_blob.csb_platform_binary = 1;
3997 tmp_blob.csb_platform_path = !!(tmp_blob.csb_flags & CS_PLATFORM_PATH);
3998 } else {
3999 tmp_blob.csb_platform_binary = 0;
4000 tmp_blob.csb_platform_path = 0;
4001 tmp_blob.csb_teamid = csblob_parse_teamid(&tmp_blob);
4002 if (cs_debug > 1) {
4003 if (tmp_blob.csb_teamid) {
4004 printf("check_signature[pid: %d]: team-id is %s\n", proc_getpid(current_proc()), tmp_blob.csb_teamid);
4005 } else {
4006 printf("check_signature[pid: %d]: no team-id\n", proc_getpid(current_proc()));
4007 }
4008 }
4009 }
4010
4011 /*
4012 * Validate the blob's coverage
4013 */
4014 blob_start_offset = tmp_blob.csb_base_offset + tmp_blob.csb_start_offset;
4015 blob_end_offset = tmp_blob.csb_base_offset + tmp_blob.csb_end_offset;
4016
4017 if (blob_start_offset >= blob_end_offset ||
4018 blob_start_offset < 0 ||
4019 blob_end_offset <= 0) {
4020 /* reject empty or backwards blob */
4021 error = EINVAL;
4022 goto out;
4023 }
4024
4025 if (ubc_cs_supports_multilevel_hash(&tmp_blob)) {
4026 error = ubc_cs_convert_to_multilevel_hash(&tmp_blob);
4027 if (error != 0) {
4028 printf("failed multilevel hash conversion: %d\n", error);
4029 goto out;
4030 }
4031 tmp_blob.csb_reconstituted = true;
4032 }
4033
4034 vnode_lock(vp);
4035 if (!UBCINFOEXISTS(vp)) {
4036 vnode_unlock(vp);
4037 error = ENOENT;
4038 goto out;
4039 }
4040 uip = vp->v_ubcinfo;
4041
4042 /* check if this new blob overlaps with an existing blob */
4043 for (oblob = ubc_get_cs_blobs(vp);
4044 oblob != NULL;
4045 oblob = oblob->csb_next) {
4046 off_t oblob_start_offset, oblob_end_offset;
4047
4048 if (tmp_blob.csb_signer_type != oblob->csb_signer_type) { // signer type needs to be the same for slices
4049 vnode_unlock(vp);
4050 error = EALREADY;
4051 goto out;
4052 } else if (tmp_blob.csb_platform_binary) { //platform binary needs to be the same for app slices
4053 if (!oblob->csb_platform_binary) {
4054 vnode_unlock(vp);
4055 error = EALREADY;
4056 goto out;
4057 }
4058 } else if (tmp_blob.csb_teamid) { //teamid binary needs to be the same for app slices
4059 if (oblob->csb_platform_binary ||
4060 oblob->csb_teamid == NULL ||
4061 strcmp(oblob->csb_teamid, tmp_blob.csb_teamid) != 0) {
4062 vnode_unlock(vp);
4063 error = EALREADY;
4064 goto out;
4065 }
4066 } else { // non teamid binary needs to be the same for app slices
4067 if (oblob->csb_platform_binary ||
4068 oblob->csb_teamid != NULL) {
4069 vnode_unlock(vp);
4070 error = EALREADY;
4071 goto out;
4072 }
4073 }
4074
4075 oblob_start_offset = (oblob->csb_base_offset +
4076 oblob->csb_start_offset);
4077 oblob_end_offset = (oblob->csb_base_offset +
4078 oblob->csb_end_offset);
4079 if (blob_start_offset >= oblob_end_offset ||
4080 blob_end_offset <= oblob_start_offset) {
4081 /* no conflict with this existing blob */
4082 } else {
4083 /* conflict ! */
4084 if (blob_start_offset == oblob_start_offset &&
4085 blob_end_offset == oblob_end_offset &&
4086 tmp_blob.csb_mem_size == oblob->csb_mem_size &&
4087 tmp_blob.csb_flags == oblob->csb_flags &&
4088 (tmp_blob.csb_cpu_type == CPU_TYPE_ANY ||
4089 oblob->csb_cpu_type == CPU_TYPE_ANY ||
4090 tmp_blob.csb_cpu_type == oblob->csb_cpu_type) &&
4091 !bcmp(tmp_blob.csb_cdhash,
4092 oblob->csb_cdhash,
4093 CS_CDHASH_LEN)) {
4094 /*
4095 * We already have this blob:
4096 * we'll return success but
4097 * throw away the new blob.
4098 */
4099 if (oblob->csb_cpu_type == CPU_TYPE_ANY) {
4100 /*
4101 * The old blob matches this one
4102 * but doesn't have any CPU type.
4103 * Update it with whatever the caller
4104 * provided this time.
4105 */
4106 cs_blob_set_cpu_type(oblob, cputype);
4107 }
4108
4109 /* The signature is still accepted, so update the
4110 * generation count. */
4111 uip->cs_add_gen = cs_blob_generation_count;
4112
4113 vnode_unlock(vp);
4114 if (ret_blob) {
4115 *ret_blob = oblob;
4116 }
4117 error = EAGAIN;
4118 goto out;
4119 } else {
4120 /* different blob: reject the new one */
4121 vnode_unlock(vp);
4122 error = EALREADY;
4123 goto out;
4124 }
4125 }
4126 }
4127
4128
4129 /* mark this vnode's VM object as having "signed pages" */
4130 kr = memory_object_signed(uip->ui_control, TRUE);
4131 if (kr != KERN_SUCCESS) {
4132 vnode_unlock(vp);
4133 error = ENOENT;
4134 goto out;
4135 }
4136
4137 if (uip->cs_blobs == NULL) {
4138 /* loading 1st blob: record the file's current "modify time" */
4139 record_mtime = TRUE;
4140 }
4141
4142 /* set the generation count for cs_blobs */
4143 uip->cs_add_gen = cs_blob_generation_count;
4144
4145 /*
4146 * Add this blob to the list of blobs for this vnode.
4147 * We always add at the front of the list and we never remove a
4148 * blob from the list, so ubc_cs_get_blobs() can return whatever
4149 * the top of the list was and that list will remain valid
4150 * while we validate a page, even after we release the vnode's lock.
4151 */
4152 tmp_blob.csb_next = uip->cs_blobs;
4153 uip->cs_blobs = blob_ro;
4154
4155 ubc_cs_blob_adjust_statistics(&tmp_blob);
4156
4157 zalloc_ro_update_elem(ZONE_ID_CS_BLOB, blob_ro, &tmp_blob);
4158
4159 if (cs_debug > 1) {
4160 proc_t p;
4161 const char *name = vnode_getname_printable(vp);
4162 p = current_proc();
4163 printf("CODE SIGNING: proc %d(%s) "
4164 "loaded %s signatures for file (%s) "
4165 "range 0x%llx:0x%llx flags 0x%x\n",
4166 proc_getpid(p), p->p_comm,
4167 blob_ro->csb_cpu_type == -1 ? "detached" : "embedded",
4168 name,
4169 blob_ro->csb_base_offset + blob_ro->csb_start_offset,
4170 blob_ro->csb_base_offset + blob_ro->csb_end_offset,
4171 blob_ro->csb_flags);
4172 vnode_putname_printable(name);
4173 }
4174
4175 vnode_unlock(vp);
4176
4177 if (record_mtime) {
4178 vnode_mtime(vp, &uip->cs_mtime, vfs_context_current());
4179 }
4180
4181 if (ret_blob) {
4182 *ret_blob = blob_ro;
4183 }
4184
4185 error = 0; /* success ! */
4186
4187 out:
4188 if (error) {
4189 if (cs_debug) {
4190 printf("check_signature[pid: %d]: error = %d\n", proc_getpid(current_proc()), error);
4191 }
4192
4193 cs_blob_cleanup(&tmp_blob);
4194 if (blob_ro) {
4195 zfree_ro(ZONE_ID_CS_BLOB, blob_ro);
4196 }
4197 }
4198
4199 if (error == EAGAIN) {
4200 /*
4201 * See above: error is EAGAIN if we were asked
4202 * to add an existing blob again. We cleaned the new
4203 * blob and we want to return success.
4204 */
4205 error = 0;
4206 }
4207
4208 return error;
4209 }
4210
4211 #if CONFIG_SUPPLEMENTAL_SIGNATURES
4212 int
ubc_cs_blob_add_supplement(struct vnode * vp,struct vnode * orig_vp,off_t base_offset,vm_address_t * addr,vm_size_t size,struct cs_blob ** ret_blob)4213 ubc_cs_blob_add_supplement(
4214 struct vnode *vp,
4215 struct vnode *orig_vp,
4216 off_t base_offset,
4217 vm_address_t *addr,
4218 vm_size_t size,
4219 struct cs_blob **ret_blob)
4220 {
4221 kern_return_t kr;
4222 struct ubc_info *uip, *orig_uip;
4223 int error;
4224 struct cs_blob tmp_blob;
4225 struct cs_blob *orig_blob;
4226 struct cs_blob *blob_ro = NULL;
4227 CS_CodeDirectory const *cd;
4228 off_t blob_start_offset, blob_end_offset;
4229
4230 if (ret_blob) {
4231 *ret_blob = NULL;
4232 }
4233
4234 /* Create the struct cs_blob wrapper that will be attached to the vnode.
4235 * Validates the passed in blob in the process. */
4236 error = cs_blob_init_validated(addr, size, &tmp_blob, &cd);
4237
4238 if (error != 0) {
4239 printf("malformed code signature supplement blob: %d\n", error);
4240 return error;
4241 }
4242
4243 tmp_blob.csb_cpu_type = -1;
4244 tmp_blob.csb_base_offset = base_offset;
4245
4246 tmp_blob.csb_reconstituted = false;
4247
4248 vnode_lock(orig_vp);
4249 if (!UBCINFOEXISTS(orig_vp)) {
4250 vnode_unlock(orig_vp);
4251 error = ENOENT;
4252 goto out;
4253 }
4254
4255 orig_uip = orig_vp->v_ubcinfo;
4256
4257 /* check that the supplement's linked cdhash matches a cdhash of
4258 * the target image.
4259 */
4260
4261 if (tmp_blob.csb_linkage_hashtype == NULL) {
4262 proc_t p;
4263 const char *iname = vnode_getname_printable(vp);
4264 p = current_proc();
4265
4266 printf("CODE SIGNING: proc %d(%s) supplemental signature for file (%s) "
4267 "is not a supplemental.\n",
4268 proc_getpid(p), p->p_comm, iname);
4269
4270 error = EINVAL;
4271
4272 vnode_putname_printable(iname);
4273 vnode_unlock(orig_vp);
4274 goto out;
4275 }
4276
4277 for (orig_blob = ubc_get_cs_blobs(orig_vp); orig_blob != NULL;
4278 orig_blob = orig_blob->csb_next) {
4279 if (orig_blob->csb_hashtype == tmp_blob.csb_linkage_hashtype &&
4280 memcmp(orig_blob->csb_cdhash, tmp_blob.csb_linkage, CS_CDHASH_LEN) == 0) {
4281 // Found match!
4282 break;
4283 }
4284 }
4285
4286 if (orig_blob == NULL) {
4287 // Not found.
4288
4289 proc_t p;
4290 const char *iname = vnode_getname_printable(vp);
4291 p = current_proc();
4292
4293 printf("CODE SIGNING: proc %d(%s) supplemental signature for file (%s) "
4294 "does not match any attached cdhash.\n",
4295 proc_getpid(p), p->p_comm, iname);
4296
4297 error = ESRCH;
4298
4299 vnode_putname_printable(iname);
4300 vnode_unlock(orig_vp);
4301 goto out;
4302 }
4303
4304 vnode_unlock(orig_vp);
4305
4306 blob_ro = zalloc_ro(ZONE_ID_CS_BLOB, Z_WAITOK | Z_NOFAIL);
4307 tmp_blob.csb_ro_addr = blob_ro;
4308 tmp_blob.csb_vnode = vp;
4309
4310 /* AMFI needs to see the current blob state at the RO address. */
4311 zalloc_ro_update_elem(ZONE_ID_CS_BLOB, blob_ro, &tmp_blob);
4312
4313 // validate the signature against policy!
4314 #if CONFIG_MACF
4315 unsigned int signer_type = tmp_blob.csb_signer_type;
4316 error = mac_vnode_check_supplemental_signature(vp, &tmp_blob, orig_vp, orig_blob, &signer_type);
4317
4318 tmp_blob.csb_signer_type = signer_type;
4319
4320 if (error) {
4321 if (cs_debug) {
4322 printf("check_supplemental_signature[pid: %d], error = %d\n", proc_getpid(current_proc()), error);
4323 }
4324 goto out;
4325 }
4326 #endif
4327
4328 // We allowed the supplemental signature blob so
4329 // copy the platform bit or team-id from the linked signature and whether or not the original is developer code
4330 tmp_blob.csb_platform_binary = 0;
4331 tmp_blob.csb_platform_path = 0;
4332 if (orig_blob->csb_platform_binary == 1) {
4333 tmp_blob.csb_platform_binary = orig_blob->csb_platform_binary;
4334 tmp_blob.csb_platform_path = orig_blob->csb_platform_path;
4335 } else if (orig_blob->csb_teamid != NULL) {
4336 vm_size_t teamid_size = strlen(orig_blob->csb_teamid) + 1;
4337 tmp_blob.csb_supplement_teamid = kalloc_data(teamid_size, Z_WAITOK);
4338 if (tmp_blob.csb_supplement_teamid == NULL) {
4339 error = ENOMEM;
4340 goto out;
4341 }
4342 strlcpy(tmp_blob.csb_supplement_teamid, orig_blob->csb_teamid, teamid_size);
4343 }
4344 tmp_blob.csb_flags = (orig_blob->csb_flags & CS_DEV_CODE);
4345
4346 // Validate the blob's coverage
4347 blob_start_offset = tmp_blob.csb_base_offset + tmp_blob.csb_start_offset;
4348 blob_end_offset = tmp_blob.csb_base_offset + tmp_blob.csb_end_offset;
4349
4350 if (blob_start_offset >= blob_end_offset || blob_start_offset < 0 || blob_end_offset <= 0) {
4351 /* reject empty or backwards blob */
4352 error = EINVAL;
4353 goto out;
4354 }
4355
4356 vnode_lock(vp);
4357 if (!UBCINFOEXISTS(vp)) {
4358 vnode_unlock(vp);
4359 error = ENOENT;
4360 goto out;
4361 }
4362 uip = vp->v_ubcinfo;
4363
4364 struct cs_blob *existing = uip->cs_blob_supplement;
4365 if (existing != NULL) {
4366 if (tmp_blob.csb_hashtype == existing->csb_hashtype &&
4367 memcmp(tmp_blob.csb_cdhash, existing->csb_cdhash, CS_CDHASH_LEN) == 0) {
4368 error = EAGAIN; // non-fatal
4369 } else {
4370 error = EALREADY; // fatal
4371 }
4372
4373 vnode_unlock(vp);
4374 goto out;
4375 }
4376
4377 /* Unlike regular cs_blobs, we only ever support one supplement. */
4378 tmp_blob.csb_next = NULL;
4379 uip->cs_blob_supplement = blob_ro;
4380
4381 /* mark this vnode's VM object as having "signed pages" */
4382 kr = memory_object_signed(uip->ui_control, TRUE);
4383 if (kr != KERN_SUCCESS) {
4384 vnode_unlock(vp);
4385 error = ENOENT;
4386 goto out;
4387 }
4388
4389 zalloc_ro_update_elem(ZONE_ID_CS_BLOB, blob_ro, &tmp_blob);
4390
4391 vnode_unlock(vp);
4392
4393 /* We still adjust statistics even for supplemental blobs, as they
4394 * consume memory just the same. */
4395 ubc_cs_blob_adjust_statistics(&tmp_blob);
4396
4397 if (cs_debug > 1) {
4398 proc_t p;
4399 const char *name = vnode_getname_printable(vp);
4400 p = current_proc();
4401 printf("CODE SIGNING: proc %d(%s) "
4402 "loaded supplemental signature for file (%s) "
4403 "range 0x%llx:0x%llx\n",
4404 proc_getpid(p), p->p_comm,
4405 name,
4406 blob_ro->csb_base_offset + blob_ro->csb_start_offset,
4407 blob_ro->csb_base_offset + blob_ro->csb_end_offset);
4408 vnode_putname_printable(name);
4409 }
4410
4411 if (ret_blob) {
4412 *ret_blob = blob_ro;
4413 }
4414
4415 error = 0; // Success!
4416 out:
4417 if (error) {
4418 if (cs_debug) {
4419 printf("ubc_cs_blob_add_supplement[pid: %d]: error = %d\n", proc_getpid(current_proc()), error);
4420 }
4421
4422 cs_blob_cleanup(&tmp_blob);
4423 if (blob_ro) {
4424 zfree_ro(ZONE_ID_CS_BLOB, blob_ro);
4425 }
4426 }
4427
4428 if (error == EAGAIN) {
4429 /* We were asked to add an existing blob.
4430 * We cleaned up and ignore the attempt. */
4431 error = 0;
4432 }
4433
4434 return error;
4435 }
4436 #endif
4437
4438
4439
4440 void
csvnode_print_debug(struct vnode * vp)4441 csvnode_print_debug(struct vnode *vp)
4442 {
4443 const char *name = NULL;
4444 struct ubc_info *uip;
4445 struct cs_blob *blob;
4446
4447 name = vnode_getname_printable(vp);
4448 if (name) {
4449 printf("csvnode: name: %s\n", name);
4450 vnode_putname_printable(name);
4451 }
4452
4453 vnode_lock_spin(vp);
4454
4455 if (!UBCINFOEXISTS(vp)) {
4456 blob = NULL;
4457 goto out;
4458 }
4459
4460 uip = vp->v_ubcinfo;
4461 for (blob = uip->cs_blobs; blob != NULL; blob = blob->csb_next) {
4462 printf("csvnode: range: %lu -> %lu flags: 0x%08x platform: %s path: %s team: %s\n",
4463 (unsigned long)blob->csb_start_offset,
4464 (unsigned long)blob->csb_end_offset,
4465 blob->csb_flags,
4466 blob->csb_platform_binary ? "yes" : "no",
4467 blob->csb_platform_path ? "yes" : "no",
4468 blob->csb_teamid ? blob->csb_teamid : "<NO-TEAM>");
4469 }
4470
4471 out:
4472 vnode_unlock(vp);
4473 }
4474
4475 #if CONFIG_SUPPLEMENTAL_SIGNATURES
4476 struct cs_blob *
ubc_cs_blob_get_supplement(struct vnode * vp,off_t offset)4477 ubc_cs_blob_get_supplement(
4478 struct vnode *vp,
4479 off_t offset)
4480 {
4481 struct cs_blob *blob;
4482 off_t offset_in_blob;
4483
4484 vnode_lock_spin(vp);
4485
4486 if (!UBCINFOEXISTS(vp)) {
4487 blob = NULL;
4488 goto out;
4489 }
4490
4491 blob = vp->v_ubcinfo->cs_blob_supplement;
4492
4493 if (blob == NULL) {
4494 // no supplemental blob
4495 goto out;
4496 }
4497
4498
4499 if (offset != -1) {
4500 offset_in_blob = offset - blob->csb_base_offset;
4501 if (offset_in_blob < blob->csb_start_offset || offset_in_blob >= blob->csb_end_offset) {
4502 // not actually covered by this blob
4503 blob = NULL;
4504 }
4505 }
4506
4507 out:
4508 vnode_unlock(vp);
4509
4510 return blob;
4511 }
4512 #endif
4513
4514 struct cs_blob *
ubc_cs_blob_get(struct vnode * vp,cpu_type_t cputype,cpu_subtype_t cpusubtype,off_t offset)4515 ubc_cs_blob_get(
4516 struct vnode *vp,
4517 cpu_type_t cputype,
4518 cpu_subtype_t cpusubtype,
4519 off_t offset)
4520 {
4521 struct cs_blob *blob;
4522 off_t offset_in_blob;
4523
4524 vnode_lock_spin(vp);
4525
4526 if (!UBCINFOEXISTS(vp)) {
4527 blob = NULL;
4528 goto out;
4529 }
4530
4531 for (blob = ubc_get_cs_blobs(vp);
4532 blob != NULL;
4533 blob = blob->csb_next) {
4534 if (cputype != -1 && blob->csb_cpu_type == cputype && (cpusubtype == -1 || blob->csb_cpu_subtype == (cpusubtype & ~CPU_SUBTYPE_MASK))) {
4535 break;
4536 }
4537 if (offset != -1) {
4538 offset_in_blob = offset - blob->csb_base_offset;
4539 if (offset_in_blob >= blob->csb_start_offset &&
4540 offset_in_blob < blob->csb_end_offset) {
4541 /* our offset is covered by this blob */
4542 break;
4543 }
4544 }
4545 }
4546
4547 out:
4548 vnode_unlock(vp);
4549
4550 return blob;
4551 }
4552
4553 static void
ubc_cs_free(struct ubc_info * uip)4554 ubc_cs_free(
4555 struct ubc_info *uip)
4556 {
4557 struct cs_blob *blob, *next_blob;
4558
4559 for (blob = uip->cs_blobs;
4560 blob != NULL;
4561 blob = next_blob) {
4562 next_blob = blob->csb_next;
4563 os_atomic_add(&cs_blob_count, -1, relaxed);
4564 os_atomic_add(&cs_blob_size, -blob->csb_mem_size, relaxed);
4565 cs_blob_ro_free(blob);
4566 }
4567 #if CHECK_CS_VALIDATION_BITMAP
4568 ubc_cs_validation_bitmap_deallocate( uip );
4569 #endif
4570 uip->cs_blobs = NULL;
4571 #if CONFIG_SUPPLEMENTAL_SIGNATURES
4572 if (uip->cs_blob_supplement != NULL) {
4573 blob = uip->cs_blob_supplement;
4574 os_atomic_add(&cs_blob_count, -1, relaxed);
4575 os_atomic_add(&cs_blob_size, -blob->csb_mem_size, relaxed);
4576 cs_blob_supplement_free(uip->cs_blob_supplement);
4577 uip->cs_blob_supplement = NULL;
4578 }
4579 #endif
4580 }
4581
4582 /* check cs blob generation on vnode
4583 * returns:
4584 * 0 : Success, the cs_blob attached is current
4585 * ENEEDAUTH : Generation count mismatch. Needs authentication again.
4586 */
4587 int
ubc_cs_generation_check(struct vnode * vp)4588 ubc_cs_generation_check(
4589 struct vnode *vp)
4590 {
4591 int retval = ENEEDAUTH;
4592
4593 vnode_lock_spin(vp);
4594
4595 if (UBCINFOEXISTS(vp) && vp->v_ubcinfo->cs_add_gen == cs_blob_generation_count) {
4596 retval = 0;
4597 }
4598
4599 vnode_unlock(vp);
4600 return retval;
4601 }
4602
4603 int
ubc_cs_blob_revalidate(struct vnode * vp,struct cs_blob * blob,struct image_params * imgp,int flags,uint32_t platform)4604 ubc_cs_blob_revalidate(
4605 struct vnode *vp,
4606 struct cs_blob *blob,
4607 struct image_params *imgp,
4608 int flags,
4609 uint32_t platform
4610 )
4611 {
4612 int error = 0;
4613 const CS_CodeDirectory *cd = NULL;
4614 const CS_GenericBlob *entitlements = NULL;
4615 const CS_GenericBlob *der_entitlements = NULL;
4616 size_t size;
4617 assert(vp != NULL);
4618 assert(blob != NULL);
4619
4620 size = blob->csb_mem_size;
4621 error = cs_validate_csblob((const uint8_t *)blob->csb_mem_kaddr,
4622 size, &cd, &entitlements, &der_entitlements);
4623 if (error) {
4624 if (cs_debug) {
4625 printf("CODESIGNING: csblob invalid: %d\n", error);
4626 }
4627 goto out;
4628 }
4629
4630 unsigned int cs_flags = (ntohl(cd->flags) & CS_ALLOWED_MACHO) | CS_VALID;
4631 unsigned int signer_type = CS_SIGNER_TYPE_UNKNOWN;
4632
4633 if (blob->csb_reconstituted) {
4634 /*
4635 * Code signatures that have been modified after validation
4636 * cannot be revalidated inline from their in-memory blob.
4637 *
4638 * That's okay, though, because the only path left that relies
4639 * on revalidation of existing in-memory blobs is the legacy
4640 * detached signature database path, which only exists on macOS,
4641 * which does not do reconstitution of any kind.
4642 */
4643 if (cs_debug) {
4644 printf("CODESIGNING: revalidate: not inline revalidating reconstituted signature.\n");
4645 }
4646
4647 /*
4648 * EAGAIN tells the caller that they may reread the code
4649 * signature and try attaching it again, which is the same
4650 * thing they would do if there was no cs_blob yet in the
4651 * first place.
4652 *
4653 * Conveniently, after ubc_cs_blob_add did a successful
4654 * validation, it will detect that a matching cs_blob (cdhash,
4655 * offset, arch etc.) already exists, and return success
4656 * without re-adding a cs_blob to the vnode.
4657 */
4658 return EAGAIN;
4659 }
4660
4661 /* callout to mac_vnode_check_signature */
4662 #if CONFIG_MACF
4663 error = mac_vnode_check_signature(vp, blob, imgp, &cs_flags, &signer_type, flags, platform);
4664 if (cs_debug && error) {
4665 printf("revalidate: check_signature[pid: %d], error = %d\n", proc_getpid(current_proc()), error);
4666 }
4667 #else
4668 (void)flags;
4669 (void)signer_type;
4670 #endif
4671
4672 /* update generation number if success */
4673 vnode_lock_spin(vp);
4674 struct cs_signer_info signer_info = {
4675 .csb_flags = cs_flags,
4676 .csb_signer_type = signer_type
4677 };
4678 zalloc_ro_update_field(ZONE_ID_CS_BLOB, blob, csb_signer_info, &signer_info);
4679 if (UBCINFOEXISTS(vp)) {
4680 if (error == 0) {
4681 vp->v_ubcinfo->cs_add_gen = cs_blob_generation_count;
4682 } else {
4683 vp->v_ubcinfo->cs_add_gen = 0;
4684 }
4685 }
4686
4687 vnode_unlock(vp);
4688
4689 out:
4690 return error;
4691 }
4692
4693 void
cs_blob_reset_cache()4694 cs_blob_reset_cache()
4695 {
4696 /* incrementing odd no by 2 makes sure '0' is never reached. */
4697 OSAddAtomic(+2, &cs_blob_generation_count);
4698 printf("Reseting cs_blob cache from all vnodes. \n");
4699 }
4700
4701 struct cs_blob *
ubc_get_cs_blobs(struct vnode * vp)4702 ubc_get_cs_blobs(
4703 struct vnode *vp)
4704 {
4705 struct ubc_info *uip;
4706 struct cs_blob *blobs;
4707
4708 /*
4709 * No need to take the vnode lock here. The caller must be holding
4710 * a reference on the vnode (via a VM mapping or open file descriptor),
4711 * so the vnode will not go away. The ubc_info stays until the vnode
4712 * goes away. And we only modify "blobs" by adding to the head of the
4713 * list.
4714 * The ubc_info could go away entirely if the vnode gets reclaimed as
4715 * part of a forced unmount. In the case of a code-signature validation
4716 * during a page fault, the "paging_in_progress" reference on the VM
4717 * object guarantess that the vnode pager (and the ubc_info) won't go
4718 * away during the fault.
4719 * Other callers need to protect against vnode reclaim by holding the
4720 * vnode lock, for example.
4721 */
4722
4723 if (!UBCINFOEXISTS(vp)) {
4724 blobs = NULL;
4725 goto out;
4726 }
4727
4728 uip = vp->v_ubcinfo;
4729 blobs = uip->cs_blobs;
4730 if (blobs != NULL) {
4731 cs_blob_require(blobs, vp);
4732 }
4733
4734 out:
4735 return blobs;
4736 }
4737
4738 #if CONFIG_SUPPLEMENTAL_SIGNATURES
4739 struct cs_blob *
ubc_get_cs_supplement(struct vnode * vp)4740 ubc_get_cs_supplement(
4741 struct vnode *vp)
4742 {
4743 struct ubc_info *uip;
4744 struct cs_blob *blob;
4745
4746 /*
4747 * No need to take the vnode lock here. The caller must be holding
4748 * a reference on the vnode (via a VM mapping or open file descriptor),
4749 * so the vnode will not go away. The ubc_info stays until the vnode
4750 * goes away.
4751 * The ubc_info could go away entirely if the vnode gets reclaimed as
4752 * part of a forced unmount. In the case of a code-signature validation
4753 * during a page fault, the "paging_in_progress" reference on the VM
4754 * object guarantess that the vnode pager (and the ubc_info) won't go
4755 * away during the fault.
4756 * Other callers need to protect against vnode reclaim by holding the
4757 * vnode lock, for example.
4758 */
4759
4760 if (!UBCINFOEXISTS(vp)) {
4761 blob = NULL;
4762 goto out;
4763 }
4764
4765 uip = vp->v_ubcinfo;
4766 blob = uip->cs_blob_supplement;
4767 if (blob != NULL) {
4768 cs_blob_require(blob, vp);
4769 }
4770
4771 out:
4772 return blob;
4773 }
4774 #endif
4775
4776
4777 void
ubc_get_cs_mtime(struct vnode * vp,struct timespec * cs_mtime)4778 ubc_get_cs_mtime(
4779 struct vnode *vp,
4780 struct timespec *cs_mtime)
4781 {
4782 struct ubc_info *uip;
4783
4784 if (!UBCINFOEXISTS(vp)) {
4785 cs_mtime->tv_sec = 0;
4786 cs_mtime->tv_nsec = 0;
4787 return;
4788 }
4789
4790 uip = vp->v_ubcinfo;
4791 cs_mtime->tv_sec = uip->cs_mtime.tv_sec;
4792 cs_mtime->tv_nsec = uip->cs_mtime.tv_nsec;
4793 }
4794
4795 unsigned long cs_validate_page_no_hash = 0;
4796 unsigned long cs_validate_page_bad_hash = 0;
4797 static boolean_t
cs_validate_hash(struct cs_blob * blobs,memory_object_t pager,memory_object_offset_t page_offset,const void * data,vm_size_t * bytes_processed,unsigned * tainted)4798 cs_validate_hash(
4799 struct cs_blob *blobs,
4800 memory_object_t pager,
4801 memory_object_offset_t page_offset,
4802 const void *data,
4803 vm_size_t *bytes_processed,
4804 unsigned *tainted)
4805 {
4806 union cs_hash_union mdctx;
4807 struct cs_hash const *hashtype = NULL;
4808 unsigned char actual_hash[CS_HASH_MAX_SIZE];
4809 unsigned char expected_hash[CS_HASH_MAX_SIZE];
4810 boolean_t found_hash;
4811 struct cs_blob *blob;
4812 const CS_CodeDirectory *cd;
4813 const unsigned char *hash;
4814 boolean_t validated;
4815 off_t offset; /* page offset in the file */
4816 size_t size;
4817 off_t codeLimit = 0;
4818 const char *lower_bound, *upper_bound;
4819 vm_offset_t kaddr, blob_addr;
4820
4821 /* retrieve the expected hash */
4822 found_hash = FALSE;
4823
4824 for (blob = blobs;
4825 blob != NULL;
4826 blob = blob->csb_next) {
4827 offset = page_offset - blob->csb_base_offset;
4828 if (offset < blob->csb_start_offset ||
4829 offset >= blob->csb_end_offset) {
4830 /* our page is not covered by this blob */
4831 continue;
4832 }
4833
4834 /* blob data has been released */
4835 kaddr = (vm_offset_t)blob->csb_mem_kaddr;
4836 if (kaddr == 0) {
4837 continue;
4838 }
4839
4840 blob_addr = kaddr + blob->csb_mem_offset;
4841 lower_bound = CAST_DOWN(char *, blob_addr);
4842 upper_bound = lower_bound + blob->csb_mem_size;
4843
4844 cd = blob->csb_cd;
4845 if (cd != NULL) {
4846 /* all CD's that have been injected is already validated */
4847
4848 hashtype = blob->csb_hashtype;
4849 if (hashtype == NULL) {
4850 panic("unknown hash type ?");
4851 }
4852 if (hashtype->cs_digest_size > sizeof(actual_hash)) {
4853 panic("hash size too large");
4854 }
4855 if (offset & ((1U << blob->csb_hash_pageshift) - 1)) {
4856 panic("offset not aligned to cshash boundary");
4857 }
4858
4859 codeLimit = ntohl(cd->codeLimit);
4860
4861 hash = hashes(cd, (uint32_t)(offset >> blob->csb_hash_pageshift),
4862 hashtype->cs_size,
4863 lower_bound, upper_bound);
4864 if (hash != NULL) {
4865 bcopy(hash, expected_hash, hashtype->cs_size);
4866 found_hash = TRUE;
4867 }
4868
4869 break;
4870 }
4871 }
4872
4873 if (found_hash == FALSE) {
4874 /*
4875 * We can't verify this page because there is no signature
4876 * for it (yet). It's possible that this part of the object
4877 * is not signed, or that signatures for that part have not
4878 * been loaded yet.
4879 * Report that the page has not been validated and let the
4880 * caller decide if it wants to accept it or not.
4881 */
4882 cs_validate_page_no_hash++;
4883 if (cs_debug > 1) {
4884 printf("CODE SIGNING: cs_validate_page: "
4885 "mobj %p off 0x%llx: no hash to validate !?\n",
4886 pager, page_offset);
4887 }
4888 validated = FALSE;
4889 *tainted = 0;
4890 } else {
4891 *tainted = 0;
4892
4893 size = (1U << blob->csb_hash_pageshift);
4894 *bytes_processed = size;
4895
4896 const uint32_t *asha1, *esha1;
4897 if ((off_t)(offset + size) > codeLimit) {
4898 /* partial page at end of segment */
4899 assert(offset < codeLimit);
4900 size = (size_t) (codeLimit & (size - 1));
4901 *tainted |= CS_VALIDATE_NX;
4902 }
4903
4904 hashtype->cs_init(&mdctx);
4905
4906 if (blob->csb_hash_firstlevel_pageshift) {
4907 const unsigned char *partial_data = (const unsigned char *)data;
4908 size_t i;
4909 for (i = 0; i < size;) {
4910 union cs_hash_union partialctx;
4911 unsigned char partial_digest[CS_HASH_MAX_SIZE];
4912 size_t partial_size = MIN(size - i, (1U << blob->csb_hash_firstlevel_pageshift));
4913
4914 hashtype->cs_init(&partialctx);
4915 hashtype->cs_update(&partialctx, partial_data, partial_size);
4916 hashtype->cs_final(partial_digest, &partialctx);
4917
4918 /* Update cumulative multi-level hash */
4919 hashtype->cs_update(&mdctx, partial_digest, hashtype->cs_size);
4920 partial_data = partial_data + partial_size;
4921 i += partial_size;
4922 }
4923 } else {
4924 hashtype->cs_update(&mdctx, data, size);
4925 }
4926 hashtype->cs_final(actual_hash, &mdctx);
4927
4928 asha1 = (const uint32_t *) actual_hash;
4929 esha1 = (const uint32_t *) expected_hash;
4930
4931 if (bcmp(expected_hash, actual_hash, hashtype->cs_size) != 0) {
4932 if (cs_debug) {
4933 printf("CODE SIGNING: cs_validate_page: "
4934 "mobj %p off 0x%llx size 0x%lx: "
4935 "actual [0x%x 0x%x 0x%x 0x%x 0x%x] != "
4936 "expected [0x%x 0x%x 0x%x 0x%x 0x%x]\n",
4937 pager, page_offset, size,
4938 asha1[0], asha1[1], asha1[2],
4939 asha1[3], asha1[4],
4940 esha1[0], esha1[1], esha1[2],
4941 esha1[3], esha1[4]);
4942 }
4943 cs_validate_page_bad_hash++;
4944 *tainted |= CS_VALIDATE_TAINTED;
4945 } else {
4946 if (cs_debug > 10) {
4947 printf("CODE SIGNING: cs_validate_page: "
4948 "mobj %p off 0x%llx size 0x%lx: "
4949 "SHA1 OK\n",
4950 pager, page_offset, size);
4951 }
4952 }
4953 validated = TRUE;
4954 }
4955
4956 return validated;
4957 }
4958
4959 boolean_t
cs_validate_range(struct vnode * vp,memory_object_t pager,memory_object_offset_t page_offset,const void * data,vm_size_t dsize,unsigned * tainted)4960 cs_validate_range(
4961 struct vnode *vp,
4962 memory_object_t pager,
4963 memory_object_offset_t page_offset,
4964 const void *data,
4965 vm_size_t dsize,
4966 unsigned *tainted)
4967 {
4968 vm_size_t offset_in_range;
4969 boolean_t all_subranges_validated = TRUE; /* turn false if any subrange fails */
4970
4971 struct cs_blob *blobs = ubc_get_cs_blobs(vp);
4972
4973 #if CONFIG_SUPPLEMENTAL_SIGNATURES
4974 if (blobs == NULL && proc_is_translated(current_proc())) {
4975 struct cs_blob *supp = ubc_get_cs_supplement(vp);
4976
4977 if (supp != NULL) {
4978 blobs = supp;
4979 } else {
4980 return FALSE;
4981 }
4982 }
4983 #endif
4984
4985
4986
4987 *tainted = 0;
4988
4989 for (offset_in_range = 0;
4990 offset_in_range < dsize;
4991 /* offset_in_range updated based on bytes processed */) {
4992 unsigned subrange_tainted = 0;
4993 boolean_t subrange_validated;
4994 vm_size_t bytes_processed = 0;
4995
4996 subrange_validated = cs_validate_hash(blobs,
4997 pager,
4998 page_offset + offset_in_range,
4999 (const void *)((const char *)data + offset_in_range),
5000 &bytes_processed,
5001 &subrange_tainted);
5002
5003 *tainted |= subrange_tainted;
5004
5005 if (bytes_processed == 0) {
5006 /* Cannote make forward progress, so return an error */
5007 all_subranges_validated = FALSE;
5008 break;
5009 } else if (subrange_validated == FALSE) {
5010 all_subranges_validated = FALSE;
5011 /* Keep going to detect other types of failures in subranges */
5012 }
5013
5014 offset_in_range += bytes_processed;
5015 }
5016
5017 return all_subranges_validated;
5018 }
5019
5020 void
cs_validate_page(struct vnode * vp,memory_object_t pager,memory_object_offset_t page_offset,const void * data,int * validated_p,int * tainted_p,int * nx_p)5021 cs_validate_page(
5022 struct vnode *vp,
5023 memory_object_t pager,
5024 memory_object_offset_t page_offset,
5025 const void *data,
5026 int *validated_p,
5027 int *tainted_p,
5028 int *nx_p)
5029 {
5030 vm_size_t offset_in_page;
5031 struct cs_blob *blobs;
5032
5033 blobs = ubc_get_cs_blobs(vp);
5034
5035 #if CONFIG_SUPPLEMENTAL_SIGNATURES
5036 if (blobs == NULL && proc_is_translated(current_proc())) {
5037 struct cs_blob *supp = ubc_get_cs_supplement(vp);
5038
5039 if (supp != NULL) {
5040 blobs = supp;
5041 }
5042 }
5043 #endif
5044
5045 *validated_p = VMP_CS_ALL_FALSE;
5046 *tainted_p = VMP_CS_ALL_FALSE;
5047 *nx_p = VMP_CS_ALL_FALSE;
5048
5049 for (offset_in_page = 0;
5050 offset_in_page < PAGE_SIZE;
5051 /* offset_in_page updated based on bytes processed */) {
5052 unsigned subrange_tainted = 0;
5053 boolean_t subrange_validated;
5054 vm_size_t bytes_processed = 0;
5055 int sub_bit;
5056
5057 subrange_validated = cs_validate_hash(blobs,
5058 pager,
5059 page_offset + offset_in_page,
5060 (const void *)((const char *)data + offset_in_page),
5061 &bytes_processed,
5062 &subrange_tainted);
5063
5064 if (bytes_processed == 0) {
5065 /* 4k chunk not code-signed: try next one */
5066 offset_in_page += FOURK_PAGE_SIZE;
5067 continue;
5068 }
5069 if (offset_in_page == 0 &&
5070 bytes_processed > PAGE_SIZE - FOURK_PAGE_SIZE) {
5071 /* all processed: no 4k granularity */
5072 if (subrange_validated) {
5073 *validated_p = VMP_CS_ALL_TRUE;
5074 }
5075 if (subrange_tainted & CS_VALIDATE_TAINTED) {
5076 *tainted_p = VMP_CS_ALL_TRUE;
5077 }
5078 if (subrange_tainted & CS_VALIDATE_NX) {
5079 *nx_p = VMP_CS_ALL_TRUE;
5080 }
5081 break;
5082 }
5083 /* we only handle 4k or 16k code-signing granularity... */
5084 assertf(bytes_processed <= FOURK_PAGE_SIZE,
5085 "vp %p blobs %p offset 0x%llx + 0x%llx bytes_processed 0x%llx\n",
5086 vp, blobs, (uint64_t)page_offset,
5087 (uint64_t)offset_in_page, (uint64_t)bytes_processed);
5088 sub_bit = 1 << (offset_in_page >> FOURK_PAGE_SHIFT);
5089 if (subrange_validated) {
5090 *validated_p |= sub_bit;
5091 }
5092 if (subrange_tainted & CS_VALIDATE_TAINTED) {
5093 *tainted_p |= sub_bit;
5094 }
5095 if (subrange_tainted & CS_VALIDATE_NX) {
5096 *nx_p |= sub_bit;
5097 }
5098 /* go to next 4k chunk */
5099 offset_in_page += FOURK_PAGE_SIZE;
5100 }
5101
5102 return;
5103 }
5104
5105 int
ubc_cs_getcdhash(vnode_t vp,off_t offset,unsigned char * cdhash)5106 ubc_cs_getcdhash(
5107 vnode_t vp,
5108 off_t offset,
5109 unsigned char *cdhash)
5110 {
5111 struct cs_blob *blobs, *blob;
5112 off_t rel_offset;
5113 int ret;
5114
5115 vnode_lock(vp);
5116
5117 blobs = ubc_get_cs_blobs(vp);
5118 for (blob = blobs;
5119 blob != NULL;
5120 blob = blob->csb_next) {
5121 /* compute offset relative to this blob */
5122 rel_offset = offset - blob->csb_base_offset;
5123 if (rel_offset >= blob->csb_start_offset &&
5124 rel_offset < blob->csb_end_offset) {
5125 /* this blob does cover our "offset" ! */
5126 break;
5127 }
5128 }
5129
5130 if (blob == NULL) {
5131 /* we didn't find a blob covering "offset" */
5132 ret = EBADEXEC; /* XXX any better error ? */
5133 } else {
5134 /* get the SHA1 hash of that blob */
5135 bcopy(blob->csb_cdhash, cdhash, sizeof(blob->csb_cdhash));
5136 ret = 0;
5137 }
5138
5139 vnode_unlock(vp);
5140
5141 return ret;
5142 }
5143
5144 boolean_t
ubc_cs_is_range_codesigned(vnode_t vp,mach_vm_offset_t start,mach_vm_size_t size)5145 ubc_cs_is_range_codesigned(
5146 vnode_t vp,
5147 mach_vm_offset_t start,
5148 mach_vm_size_t size)
5149 {
5150 struct cs_blob *csblob;
5151 mach_vm_offset_t blob_start;
5152 mach_vm_offset_t blob_end;
5153
5154 if (vp == NULL) {
5155 /* no file: no code signature */
5156 return FALSE;
5157 }
5158 if (size == 0) {
5159 /* no range: no code signature */
5160 return FALSE;
5161 }
5162 if (start + size < start) {
5163 /* overflow */
5164 return FALSE;
5165 }
5166
5167 csblob = ubc_cs_blob_get(vp, -1, -1, start);
5168 if (csblob == NULL) {
5169 return FALSE;
5170 }
5171
5172 /*
5173 * We currently check if the range is covered by a single blob,
5174 * which should always be the case for the dyld shared cache.
5175 * If we ever want to make this routine handle other cases, we
5176 * would have to iterate if the blob does not cover the full range.
5177 */
5178 blob_start = (mach_vm_offset_t) (csblob->csb_base_offset +
5179 csblob->csb_start_offset);
5180 blob_end = (mach_vm_offset_t) (csblob->csb_base_offset +
5181 csblob->csb_end_offset);
5182 if (blob_start > start || blob_end < (start + size)) {
5183 /* range not fully covered by this code-signing blob */
5184 return FALSE;
5185 }
5186
5187 return TRUE;
5188 }
5189
5190 #if CHECK_CS_VALIDATION_BITMAP
5191 #define stob(s) (((atop_64(round_page_64(s))) + 07) >> 3)
5192 extern boolean_t root_fs_upgrade_try;
5193
5194 /*
5195 * Should we use the code-sign bitmap to avoid repeated code-sign validation?
5196 * Depends:
5197 * a) Is the target vnode on the root filesystem?
5198 * b) Has someone tried to mount the root filesystem read-write?
5199 * If answers are (a) yes AND (b) no, then we can use the bitmap.
5200 */
5201 #define USE_CODE_SIGN_BITMAP(vp) ( (vp != NULL) && (vp->v_mount != NULL) && (vp->v_mount->mnt_flag & MNT_ROOTFS) && !root_fs_upgrade_try)
5202 kern_return_t
ubc_cs_validation_bitmap_allocate(vnode_t vp)5203 ubc_cs_validation_bitmap_allocate(
5204 vnode_t vp)
5205 {
5206 kern_return_t kr = KERN_SUCCESS;
5207 struct ubc_info *uip;
5208 char *target_bitmap;
5209 vm_object_size_t bitmap_size;
5210
5211 if (!USE_CODE_SIGN_BITMAP(vp) || (!UBCINFOEXISTS(vp))) {
5212 kr = KERN_INVALID_ARGUMENT;
5213 } else {
5214 uip = vp->v_ubcinfo;
5215
5216 if (uip->cs_valid_bitmap == NULL) {
5217 bitmap_size = stob(uip->ui_size);
5218 target_bitmap = (char*) kalloc_data((vm_size_t)bitmap_size, Z_WAITOK | Z_ZERO);
5219 if (target_bitmap == 0) {
5220 kr = KERN_NO_SPACE;
5221 } else {
5222 kr = KERN_SUCCESS;
5223 }
5224 if (kr == KERN_SUCCESS) {
5225 uip->cs_valid_bitmap = (void*)target_bitmap;
5226 uip->cs_valid_bitmap_size = bitmap_size;
5227 }
5228 }
5229 }
5230 return kr;
5231 }
5232
5233 kern_return_t
ubc_cs_check_validation_bitmap(vnode_t vp,memory_object_offset_t offset,int optype)5234 ubc_cs_check_validation_bitmap(
5235 vnode_t vp,
5236 memory_object_offset_t offset,
5237 int optype)
5238 {
5239 kern_return_t kr = KERN_SUCCESS;
5240
5241 if (!USE_CODE_SIGN_BITMAP(vp) || !UBCINFOEXISTS(vp)) {
5242 kr = KERN_INVALID_ARGUMENT;
5243 } else {
5244 struct ubc_info *uip = vp->v_ubcinfo;
5245 char *target_bitmap = uip->cs_valid_bitmap;
5246
5247 if (target_bitmap == NULL) {
5248 kr = KERN_INVALID_ARGUMENT;
5249 } else {
5250 uint64_t bit, byte;
5251 bit = atop_64( offset );
5252 byte = bit >> 3;
5253
5254 if (byte > uip->cs_valid_bitmap_size) {
5255 kr = KERN_INVALID_ARGUMENT;
5256 } else {
5257 if (optype == CS_BITMAP_SET) {
5258 target_bitmap[byte] |= (1 << (bit & 07));
5259 kr = KERN_SUCCESS;
5260 } else if (optype == CS_BITMAP_CLEAR) {
5261 target_bitmap[byte] &= ~(1 << (bit & 07));
5262 kr = KERN_SUCCESS;
5263 } else if (optype == CS_BITMAP_CHECK) {
5264 if (target_bitmap[byte] & (1 << (bit & 07))) {
5265 kr = KERN_SUCCESS;
5266 } else {
5267 kr = KERN_FAILURE;
5268 }
5269 }
5270 }
5271 }
5272 }
5273 return kr;
5274 }
5275
5276 void
ubc_cs_validation_bitmap_deallocate(struct ubc_info * uip)5277 ubc_cs_validation_bitmap_deallocate(
5278 struct ubc_info *uip)
5279 {
5280 if (uip->cs_valid_bitmap != NULL) {
5281 kfree_data(uip->cs_valid_bitmap, (vm_size_t)uip->cs_valid_bitmap_size);
5282 uip->cs_valid_bitmap = NULL;
5283 }
5284 }
5285 #else
5286 kern_return_t
ubc_cs_validation_bitmap_allocate(__unused vnode_t vp)5287 ubc_cs_validation_bitmap_allocate(__unused vnode_t vp)
5288 {
5289 return KERN_INVALID_ARGUMENT;
5290 }
5291
5292 kern_return_t
ubc_cs_check_validation_bitmap(__unused struct vnode * vp,__unused memory_object_offset_t offset,__unused int optype)5293 ubc_cs_check_validation_bitmap(
5294 __unused struct vnode *vp,
5295 __unused memory_object_offset_t offset,
5296 __unused int optype)
5297 {
5298 return KERN_INVALID_ARGUMENT;
5299 }
5300
5301 void
ubc_cs_validation_bitmap_deallocate(__unused struct ubc_info * uip)5302 ubc_cs_validation_bitmap_deallocate(__unused struct ubc_info *uip)
5303 {
5304 return;
5305 }
5306 #endif /* CHECK_CS_VALIDATION_BITMAP */
5307
5308