2 * Copyright (c) 2011-2018 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
33 #include <kern/debug.h>
34 #include <kern/trustcache.h>
35 #include <kern/misc_protos.h>
37 #include <libkern/section_keywords.h>
39 #include <mach/machine/vm_types.h>
41 #include <pexpert/device_tree.h>
43 #include <sys/cdefs.h>
45 // All the external+engineering trust caches (accepting only one on RELEASE).
46 SECURITY_READ_ONLY_LATE(static struct serialized_trust_caches
*)pmap_serialized_trust_caches
= NULL
;
48 // Shortcut to the first (= non-engineering, and therefore "static") trust cache.
49 SECURITY_READ_ONLY_LATE(static struct trust_cache_module1
*)pmap_static_trust_cache
= NULL
;
51 #if CONFIG_SECOND_STATIC_TRUST_CACHE
52 SECURITY_READ_ONLY_LATE(static struct trust_cache_module1
*)pmap_secondary_static_trust_cache
= NULL
;
55 // The EXTRADATA segment is where we find the external trust cache.
56 extern vm_offset_t segEXTRADATA
;
57 extern unsigned long segSizeEXTRADATA
;
60 trust_cache_init(void)
62 size_t const locked_down_dt_size
= SecureDTIsLockedDown() ? PE_state
.deviceTreeSize
: 0;
63 size_t const len
= segSizeEXTRADATA
- locked_down_dt_size
;
66 // We allow no trust cache at all.
67 printf("No external trust cache found (region len is 0).");
71 pmap_serialized_trust_caches
= (struct serialized_trust_caches
*)(segEXTRADATA
+
74 uint8_t const *region_end
= (uint8_t*)pmap_serialized_trust_caches
+ len
;
76 /* Validate the trust cache region for consistency.
78 * Technically, this shouldn't be necessary because any problem
79 * here would indicate that iBoot is either broken or compromised,
80 * but we do it anyway to assist in development, and for defense
84 if (len
< sizeof(struct serialized_trust_caches
)) {
85 panic("short serialized trust cache region: %zu", len
);
88 printf("%d external trust cache modules available.\n", pmap_serialized_trust_caches
->num_caches
);
90 if (len
< (sizeof(struct serialized_trust_caches
) +
91 pmap_serialized_trust_caches
->num_caches
* sizeof(uint32_t))) {
92 panic("serialized trust cache region too short for its %d entries: %zu",
93 pmap_serialized_trust_caches
->num_caches
, len
);
96 uint8_t *module_end
= (uint8_t*)pmap_serialized_trust_caches
;
98 for (uint32_t i
= 0; i
< pmap_serialized_trust_caches
->num_caches
; i
++) {
99 struct trust_cache_module1
*module = (struct trust_cache_module1
*)
100 ((uint8_t*)pmap_serialized_trust_caches
+ pmap_serialized_trust_caches
->offsets
[i
]);
102 if ((uint8_t*)module < module_end
) {
103 panic("trust cache module %d overlaps previous module", i
);
106 module_end
= (uint8_t*)(module + 1);
108 if (module_end
> region_end
) {
109 panic("trust cache module %d too short for header", i
);
112 if (module->version
!= 1) {
113 panic("trust cache module %d has unsupported version %d", i
, module->version
);
116 module_end
+= module->num_entries
* sizeof(struct trust_cache_entry1
);
118 if (module_end
> region_end
) {
119 panic("trust cache module %d too short for its %u entries", i
, module->num_entries
);
122 printf("external trust cache module %d with %d entries\n", i
, module->num_entries
);
125 pmap_static_trust_cache
= module;
127 #if CONFIG_SECOND_STATIC_TRUST_CACHE
129 pmap_secondary_static_trust_cache
= module;
136 // Lookup cdhash in a trust cache module.
137 // Suitable for all kinds of trust caches (but loadable ones are currently different).
139 lookup_in_trust_cache_module(
140 struct trust_cache_module1
const * const module,
141 uint8_t const cdhash
[CS_CDHASH_LEN
],
142 uint8_t * const hash_type
,
143 uint8_t * const flags
)
146 struct trust_cache_entry1
const *base
= &module->entries
[0];
148 struct trust_cache_entry1
const *entry
= NULL
;
152 /* Initialization already (redundantly) verified the size of the module for us. */
153 for (lim
= module->num_entries
; lim
!= 0; lim
>>= 1) {
154 entry
= base
+ (lim
>> 1);
155 int cmp
= memcmp(cdhash
, entry
->cdhash
, CS_CDHASH_LEN
);
160 if (cmp
> 0) { /* key > p: move right */
163 } /* else move left */
167 *hash_type
= entry
->hash_type
;
168 *flags
= entry
->flags
;
175 MARK_AS_PMAP_TEXT
uint32_t
176 lookup_in_static_trust_cache(const uint8_t cdhash
[CS_CDHASH_LEN
])
178 /* We will cram those into a single return value, because output parameters require
179 * some contortion. */
180 uint8_t hash_type
= 0, flags
= 0;
181 uint32_t engineering_trust_cache_index
= 1;
183 if (pmap_static_trust_cache
!= NULL
) {
184 // The one real new static trust cache.
185 if (lookup_in_trust_cache_module(pmap_static_trust_cache
, cdhash
, &hash_type
, &flags
)) {
186 return (hash_type
<< TC_LOOKUP_HASH_TYPE_SHIFT
) |
187 (flags
<< TC_LOOKUP_FLAGS_SHIFT
) |
188 (TC_LOOKUP_FOUND
<< TC_LOOKUP_RESULT_SHIFT
);
190 #if CONFIG_SECOND_STATIC_TRUST_CACHE
191 if (pmap_secondary_static_trust_cache
!= NULL
&&
192 lookup_in_trust_cache_module(pmap_secondary_static_trust_cache
, cdhash
, &hash_type
, &flags
)) {
193 return (hash_type
<< TC_LOOKUP_HASH_TYPE_SHIFT
) |
194 (flags
<< TC_LOOKUP_FLAGS_SHIFT
) |
195 (TC_LOOKUP_FOUND
<< TC_LOOKUP_RESULT_SHIFT
);
197 engineering_trust_cache_index
= (pmap_secondary_static_trust_cache
!= NULL
) ? 2 : 1;
200 // Engineering Trust Caches.
201 if (pmap_serialized_trust_caches
->num_caches
> engineering_trust_cache_index
) {
202 for (uint32_t i
= engineering_trust_cache_index
; i
< pmap_serialized_trust_caches
->num_caches
; i
++) {
203 struct trust_cache_module1
const *module =
204 (struct trust_cache_module1
const *)(
205 (uint8_t*)pmap_serialized_trust_caches
+ pmap_serialized_trust_caches
->offsets
[i
]);
207 if (lookup_in_trust_cache_module(module, cdhash
, &hash_type
, &flags
)) {
208 return (hash_type
<< TC_LOOKUP_HASH_TYPE_SHIFT
) |
209 (flags
<< TC_LOOKUP_FLAGS_SHIFT
) |
210 (TC_LOOKUP_FOUND
<< TC_LOOKUP_RESULT_SHIFT
);