File: | 3rdparty/vboot/firmware/2lib/2load_kernel.c |
Warning: | line 303, column 4 Value stored to 'keyblock_valid' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Copyright 2013 The ChromiumOS Authors |
2 | * Use of this source code is governed by a BSD-style license that can be |
3 | * found in the LICENSE file. |
4 | * |
5 | * Functions for loading a kernel from disk. |
6 | * (Firmware portion) |
7 | */ |
8 | |
9 | #include "2api.h" |
10 | #include "2common.h" |
11 | #include "2misc.h" |
12 | #include "2nvstorage.h" |
13 | #include "2packed_key.h" |
14 | #include "2secdata.h" |
15 | #include "2sysincludes.h" |
16 | #include "cgptlib.h" |
17 | #include "cgptlib_internal.h" |
18 | #include "gpt_misc.h" |
19 | #include "vboot_api.h" |
20 | |
21 | enum vb2_load_partition_flags { |
22 | VB2_LOAD_PARTITION_FLAG_VBLOCK_ONLY = (1 << 0), |
23 | VB2_LOAD_PARTITION_FLAG_MINIOS = (1 << 1), |
24 | }; |
25 | |
26 | #define KBUF_SIZE65536 65536 /* Bytes to read at start of kernel partition */ |
27 | |
28 | /* Minimum context work buffer size needed for vb2_load_partition() */ |
29 | #define VB2_LOAD_PARTITION_WORKBUF_BYTES((64 + ({ typeof((3 * 1024)) __vb2_max_a = ((3 * 1024)); typeof (sizeof(struct vb2_digest_context)) __vb2_max_b = (sizeof(struct vb2_digest_context)); __vb2_max_a > __vb2_max_b ? __vb2_max_a : __vb2_max_b; })) + 65536) \ |
30 | (VB2_VERIFY_KERNEL_PREAMBLE_WORKBUF_BYTES(64 + ({ typeof((3 * 1024)) __vb2_max_a = ((3 * 1024)); typeof (sizeof(struct vb2_digest_context)) __vb2_max_b = (sizeof(struct vb2_digest_context)); __vb2_max_a > __vb2_max_b ? __vb2_max_a : __vb2_max_b; })) + KBUF_SIZE65536) |
31 | |
32 | #define LOWEST_TPM_VERSION0xffffffff 0xffffffff |
33 | |
34 | /** |
35 | * Check if a valid keyblock is required. |
36 | * |
37 | * @param ctx Vboot context |
38 | * @return 1 if valid keyblock required (officially signed kernel); |
39 | * 0 if valid hash is enough (self-signed kernel). |
40 | */ |
41 | static int need_valid_keyblock(struct vb2_context *ctx) |
42 | { |
43 | /* Normal and recovery modes always require official OS */ |
44 | if (ctx->boot_mode != VB2_BOOT_MODE_DEVELOPER) |
45 | return 1; |
46 | |
47 | /* FWMP can require developer mode to use signed kernels */ |
48 | if (vb2_secdata_fwmp_get_flag( |
49 | ctx, VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY)) |
50 | return 1; |
51 | |
52 | /* Developers may require signed kernels */ |
53 | if (vb2_nv_get(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY)) |
54 | return 1; |
55 | |
56 | return 0; |
57 | } |
58 | |
59 | /** |
60 | * Return a pointer to the keyblock inside a vblock. |
61 | * |
62 | * Must only be called during or after vb2_verify_kernel_vblock(). |
63 | * |
64 | * @param kbuf Buffer containing vblock |
65 | * @return The keyblock pointer. |
66 | */ |
67 | static struct vb2_keyblock *get_keyblock(uint8_t *kbuf) |
68 | { |
69 | return (struct vb2_keyblock *)kbuf; |
70 | } |
71 | |
72 | /** |
73 | * Return a pointer to the kernel preamble inside a vblock. |
74 | * |
75 | * Must only be called during or after vb2_verify_kernel_vblock(). |
76 | * |
77 | * @param kbuf Buffer containing vblock |
78 | * @return The kernel preamble pointer. |
79 | */ |
80 | static struct vb2_kernel_preamble *get_preamble(uint8_t *kbuf) |
81 | { |
82 | return (struct vb2_kernel_preamble *) |
83 | (kbuf + get_keyblock(kbuf)->keyblock_size); |
84 | } |
85 | |
86 | /** |
87 | * Return the offset of the kernel body from the start of the vblock. |
88 | * |
89 | * Must only be called during or after vb2_verify_kernel_vblock(). |
90 | * |
91 | * @param kbuf Buffer containing vblock |
92 | * @return The offset of the kernel body from the vblock start, in bytes. |
93 | */ |
94 | static uint32_t get_body_offset(uint8_t *kbuf) |
95 | { |
96 | return (get_keyblock(kbuf)->keyblock_size + |
97 | get_preamble(kbuf)->preamble_size); |
98 | } |
99 | |
100 | /** |
101 | * Verify developer mode key hash. |
102 | * |
103 | * @param ctx Vboot context |
104 | * @param keyblock Keyblock to verify |
105 | * @return VB2_SUCCESS, or non-zero error code. |
106 | */ |
107 | static vb2_error_t vb2_verify_kernel_dev_key_hash( |
108 | struct vb2_context *ctx, struct vb2_keyblock *keyblock) |
109 | { |
110 | struct vb2_packed_key *key = &keyblock->data_key; |
111 | uint8_t *buf = ((uint8_t *)key) + key->key_offset; |
112 | uint32_t buflen = key->key_size; |
113 | struct vb2_hash hash; |
114 | |
115 | VB2_DEBUG("Checking developer key hash.\n")vb2ex_printf(__func__, "Checking developer key hash.\n"); |
116 | VB2_TRY(vb2_hash_calculate(vb2api_hwcrypto_allowed(ctx), buf, buflen,do { vb2_error_t _vb2_try_rv = (vb2_hash_calculate(vb2api_hwcrypto_allowed (ctx), buf, buflen, VB2_HASH_SHA256, &hash)); struct vb2_context *_vb2_try_ctx = (((void*)0)); uint8_t _vb2_try_reason = (0); if (_vb2_try_rv != VB2_SUCCESS) { vb2ex_printf(__func__, "%s returned %#x\n" , "vb2_hash_calculate(vb2api_hwcrypto_allowed(ctx), buf, buflen, VB2_HASH_SHA256, &hash)" , _vb2_try_rv); if (_vb2_try_rv >= VB2_REQUEST_END && (_vb2_try_ctx) && (_vb2_try_reason) != VB2_RECOVERY_NOT_REQUESTED ) vb2api_fail(_vb2_try_ctx, _vb2_try_reason, _vb2_try_rv); return _vb2_try_rv; } } while (0) |
117 | VB2_HASH_SHA256, &hash))do { vb2_error_t _vb2_try_rv = (vb2_hash_calculate(vb2api_hwcrypto_allowed (ctx), buf, buflen, VB2_HASH_SHA256, &hash)); struct vb2_context *_vb2_try_ctx = (((void*)0)); uint8_t _vb2_try_reason = (0); if (_vb2_try_rv != VB2_SUCCESS) { vb2ex_printf(__func__, "%s returned %#x\n" , "vb2_hash_calculate(vb2api_hwcrypto_allowed(ctx), buf, buflen, VB2_HASH_SHA256, &hash)" , _vb2_try_rv); if (_vb2_try_rv >= VB2_REQUEST_END && (_vb2_try_ctx) && (_vb2_try_reason) != VB2_RECOVERY_NOT_REQUESTED ) vb2api_fail(_vb2_try_ctx, _vb2_try_reason, _vb2_try_rv); return _vb2_try_rv; } } while (0); |
118 | |
119 | uint8_t *fwmp_dev_key_hash = |
120 | vb2_secdata_fwmp_get_dev_key_hash(ctx); |
121 | if (fwmp_dev_key_hash == NULL((void*)0)) { |
122 | VB2_DEBUG("Couldn't retrieve developer key hash.\n")vb2ex_printf(__func__, "Couldn't retrieve developer key hash.\n" ); |
123 | return VB2_ERROR_KERNEL_KEYBLOCK_DEV_KEY_HASH; |
124 | } |
125 | |
126 | if (vb2_safe_memcmp(hash.sha256, fwmp_dev_key_hash, |
127 | sizeof(hash.sha256))) { |
128 | int i; |
129 | |
130 | VB2_DEBUG("Wrong developer key hash.\n")vb2ex_printf(__func__, "Wrong developer key hash.\n"); |
131 | VB2_DEBUG("Want: ")vb2ex_printf(__func__, "Want: "); |
132 | for (i = 0; i < VB2_SHA256_DIGEST_SIZE32; i++) |
133 | VB2_DEBUG_RAW("%02x ", fwmp_dev_key_hash[i])vb2ex_printf(((void*)0), "%02x ", fwmp_dev_key_hash[i]); |
134 | VB2_DEBUG_RAW("\n")vb2ex_printf(((void*)0), "\n"); |
135 | VB2_DEBUG("Got: ")vb2ex_printf(__func__, "Got: "); |
136 | for (i = 0; i < VB2_SHA256_DIGEST_SIZE32; i++) |
137 | VB2_DEBUG_RAW("%02x ", hash.sha256[i])vb2ex_printf(((void*)0), "%02x ", hash.sha256[i]); |
138 | VB2_DEBUG_RAW("\n")vb2ex_printf(((void*)0), "\n"); |
139 | |
140 | return VB2_ERROR_KERNEL_KEYBLOCK_DEV_KEY_HASH; |
141 | } |
142 | |
143 | return VB2_SUCCESS; |
144 | } |
145 | |
146 | /** |
147 | * Verify a kernel vblock. |
148 | * |
149 | * @param ctx Vboot context |
150 | * @param kbuf Buffer containing the vblock |
151 | * @param kbuf_size Size of the buffer in bytes |
152 | * @param lpflags Flags (one or more of vb2_load_partition_flags) |
153 | * @param wb Work buffer. Must be at least |
154 | * VB2_VERIFY_KERNEL_PREAMBLE_WORKBUF_BYTES bytes. |
155 | * @param kernel_version The kernel version of this vblock. |
156 | * @return VB2_SUCCESS, or non-zero error code. |
157 | */ |
158 | static vb2_error_t vb2_verify_kernel_vblock(struct vb2_context *ctx, |
159 | uint8_t *kbuf, uint32_t kbuf_size, |
160 | uint32_t lpflags, |
161 | struct vb2_workbuf *wb, |
162 | uint32_t *kernel_version) |
163 | { |
164 | struct vb2_shared_data *sd = vb2_get_sd(ctx); |
165 | |
166 | uint8_t *key_data; |
167 | uint32_t key_size; |
168 | struct vb2_public_key kernel_key; |
169 | |
170 | int need_keyblock_valid = need_valid_keyblock(ctx); |
171 | int keyblock_valid = 1; /* Assume valid */ |
172 | |
173 | vb2_error_t rv; |
174 | |
175 | /* Locate key to verify kernel. This will either be a recovery key, or |
176 | a kernel subkey passed from firmware verification. */ |
177 | key_data = vb2_member_of(sd, sd->kernel_key_offset); |
178 | key_size = sd->kernel_key_size; |
179 | VB2_TRY(vb2_unpack_key_buffer(&kernel_key, key_data, key_size))do { vb2_error_t _vb2_try_rv = (vb2_unpack_key_buffer(&kernel_key , key_data, key_size)); struct vb2_context *_vb2_try_ctx = (( (void*)0)); uint8_t _vb2_try_reason = (0); if (_vb2_try_rv != VB2_SUCCESS) { vb2ex_printf(__func__, "%s returned %#x\n", "vb2_unpack_key_buffer(&kernel_key, key_data, key_size)" , _vb2_try_rv); if (_vb2_try_rv >= VB2_REQUEST_END && (_vb2_try_ctx) && (_vb2_try_reason) != VB2_RECOVERY_NOT_REQUESTED ) vb2api_fail(_vb2_try_ctx, _vb2_try_reason, _vb2_try_rv); return _vb2_try_rv; } } while (0); |
180 | |
181 | kernel_key.allow_hwcrypto = vb2api_hwcrypto_allowed(ctx); |
182 | |
183 | /* |
184 | * Clear any previous keyblock-valid flag (for example, from a previous |
185 | * kernel where the keyblock was signed but the preamble failed |
186 | * verification). |
187 | */ |
188 | sd->flags &= ~VB2_SD_FLAG_KERNEL_SIGNED; |
189 | |
190 | /* Verify the keyblock. */ |
191 | struct vb2_keyblock *keyblock = get_keyblock(kbuf); |
192 | rv = vb2_verify_keyblock(keyblock, kbuf_size, &kernel_key, wb); |
193 | if (rv) { |
194 | VB2_DEBUG("Verifying keyblock signature failed.\n")vb2ex_printf(__func__, "Verifying keyblock signature failed.\n" ); |
195 | keyblock_valid = 0; |
196 | |
197 | /* Check if we must have an officially signed kernel */ |
198 | if (need_keyblock_valid) { |
199 | VB2_DEBUG("Self-signed kernels not enabled.\n")vb2ex_printf(__func__, "Self-signed kernels not enabled.\n"); |
200 | return rv; |
201 | } |
202 | |
203 | /* Otherwise, allow the kernel if the keyblock hash is valid */ |
204 | rv = vb2_verify_keyblock_hash(keyblock, kbuf_size, wb); |
205 | if (rv) { |
206 | VB2_DEBUG("Verifying keyblock hash failed.\n")vb2ex_printf(__func__, "Verifying keyblock hash failed.\n"); |
207 | return rv; |
208 | } |
209 | } |
210 | |
211 | /* Check the keyblock flags against boot flags. */ |
212 | if (!(keyblock->keyblock_flags & |
213 | ((ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) ? |
214 | VB2_KEYBLOCK_FLAG_DEVELOPER_10x2 : |
215 | VB2_KEYBLOCK_FLAG_DEVELOPER_00x1))) { |
216 | VB2_DEBUG("Keyblock developer flag mismatch.\n")vb2ex_printf(__func__, "Keyblock developer flag mismatch.\n"); |
217 | keyblock_valid = 0; |
218 | if (need_keyblock_valid) |
219 | return VB2_ERROR_KERNEL_KEYBLOCK_DEV_FLAG; |
220 | } |
221 | if (!(keyblock->keyblock_flags & |
222 | ((ctx->flags & VB2_CONTEXT_RECOVERY_MODE) ? |
223 | VB2_KEYBLOCK_FLAG_RECOVERY_10x8 : |
224 | VB2_KEYBLOCK_FLAG_RECOVERY_00x4))) { |
225 | VB2_DEBUG("Keyblock recovery flag mismatch.\n")vb2ex_printf(__func__, "Keyblock recovery flag mismatch.\n"); |
226 | keyblock_valid = 0; |
227 | if (need_keyblock_valid) |
228 | return VB2_ERROR_KERNEL_KEYBLOCK_REC_FLAG; |
229 | } |
230 | if (!(keyblock->keyblock_flags & |
231 | ((lpflags & VB2_LOAD_PARTITION_FLAG_MINIOS) ? |
232 | VB2_KEYBLOCK_FLAG_MINIOS_10x20 : |
233 | VB2_KEYBLOCK_FLAG_MINIOS_00x10))) { |
234 | VB2_DEBUG("Keyblock miniOS flag mismatch.\n")vb2ex_printf(__func__, "Keyblock miniOS flag mismatch.\n"); |
235 | keyblock_valid = 0; |
236 | if (need_keyblock_valid) |
237 | return VB2_ERROR_KERNEL_KEYBLOCK_MINIOS_FLAG; |
238 | } |
239 | |
240 | /* Check for rollback of key version except in recovery mode. */ |
241 | uint32_t key_version = keyblock->data_key.key_version; |
242 | if (ctx->boot_mode != VB2_BOOT_MODE_MANUAL_RECOVERY) { |
243 | if (key_version < (sd->kernel_version_secdata >> 16)) { |
244 | keyblock_valid = 0; |
245 | if (need_keyblock_valid) { |
246 | VB2_DEBUG("Key version too old.\n")vb2ex_printf(__func__, "Key version too old.\n"); |
247 | return VB2_ERROR_KERNEL_KEYBLOCK_VERSION_ROLLBACK; |
248 | } |
249 | } |
250 | if (key_version > VB2_MAX_KEY_VERSION0xffff) { |
251 | /* |
252 | * Key version is stored in 16 bits in the TPM, so key |
253 | * versions greater than 0xFFFF can't be stored |
254 | * properly. |
255 | */ |
256 | VB2_DEBUG("Key version > 0xFFFF.\n")vb2ex_printf(__func__, "Key version > 0xFFFF.\n"); |
257 | keyblock_valid = 0; |
258 | if (need_keyblock_valid) |
259 | return VB2_ERROR_KERNEL_KEYBLOCK_VERSION_RANGE; |
260 | } |
261 | } |
262 | |
263 | /* If in developer mode and using key hash, check it. */ |
264 | if (ctx->boot_mode == VB2_BOOT_MODE_DEVELOPER && |
265 | vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_USE_KEY_HASH)) { |
266 | VB2_TRY(vb2_verify_kernel_dev_key_hash(ctx, keyblock))do { vb2_error_t _vb2_try_rv = (vb2_verify_kernel_dev_key_hash (ctx, keyblock)); struct vb2_context *_vb2_try_ctx = (((void* )0)); uint8_t _vb2_try_reason = (0); if (_vb2_try_rv != VB2_SUCCESS ) { vb2ex_printf(__func__, "%s returned %#x\n", "vb2_verify_kernel_dev_key_hash(ctx, keyblock)" , _vb2_try_rv); if (_vb2_try_rv >= VB2_REQUEST_END && (_vb2_try_ctx) && (_vb2_try_reason) != VB2_RECOVERY_NOT_REQUESTED ) vb2api_fail(_vb2_try_ctx, _vb2_try_reason, _vb2_try_rv); return _vb2_try_rv; } } while (0); |
267 | } |
268 | |
269 | /* |
270 | * At this point, we've checked everything. The kernel keyblock is at |
271 | * least self-consistent, and has either a valid signature or a valid |
272 | * hash. Track if it had a valid signature (that is, would we have |
273 | * been willing to boot it even if developer mode was off). |
274 | */ |
275 | if (keyblock_valid) |
276 | sd->flags |= VB2_SD_FLAG_KERNEL_SIGNED; |
277 | |
278 | /* Get key for preamble verification from the keyblock. */ |
279 | struct vb2_public_key data_key; |
280 | rv = vb2_unpack_key(&data_key, &keyblock->data_key); |
281 | if (rv) { |
282 | VB2_DEBUG("Unable to unpack kernel data key\n")vb2ex_printf(__func__, "Unable to unpack kernel data key\n"); |
283 | return rv; |
284 | } |
285 | |
286 | data_key.allow_hwcrypto = kernel_key.allow_hwcrypto; |
287 | |
288 | /* Verify the preamble, which follows the keyblock */ |
289 | struct vb2_kernel_preamble *preamble = get_preamble(kbuf); |
290 | rv = vb2_verify_kernel_preamble(preamble, |
291 | kbuf_size - keyblock->keyblock_size, |
292 | &data_key, |
293 | wb); |
294 | if (rv) { |
295 | VB2_DEBUG("Preamble verification failed.\n")vb2ex_printf(__func__, "Preamble verification failed.\n"); |
296 | return rv; |
297 | } |
298 | |
299 | /* Rollback check for miniOS */ |
300 | if (need_keyblock_valid && (lpflags & VB2_LOAD_PARTITION_FLAG_MINIOS)) { |
301 | if (preamble->kernel_version < |
302 | (sd->kernel_version_secdata >> 24)) { |
303 | keyblock_valid = 0; |
Value stored to 'keyblock_valid' is never read | |
304 | if (need_keyblock_valid) { |
305 | VB2_DEBUG("miniOS kernel version too old.\n")vb2ex_printf(__func__, "miniOS kernel version too old.\n"); |
306 | return VB2_ERROR_KERNEL_PREAMBLE_VERSION_ROLLBACK; |
307 | } |
308 | } |
309 | if (preamble->kernel_version > 0xff) { |
310 | /* |
311 | * Key version is stored in the top 8 bits of 16 bits |
312 | * in the TPM, so key versions greater than 0xFF can't |
313 | * be stored properly. |
314 | */ |
315 | VB2_DEBUG("Key version > 0xFF.\n")vb2ex_printf(__func__, "Key version > 0xFF.\n"); |
316 | keyblock_valid = 0; |
317 | if (need_keyblock_valid) |
318 | return VB2_ERROR_KERNEL_PREAMBLE_VERSION_RANGE; |
319 | } |
320 | } |
321 | |
322 | /* |
323 | * Kernel preamble version is the lower 16 bits of the composite |
324 | * kernel version. |
325 | */ |
326 | if (preamble->kernel_version > VB2_MAX_PREAMBLE_VERSION0xffff) |
327 | return VB2_ERROR_KERNEL_PREAMBLE_VERSION_RANGE; |
328 | |
329 | /* Combine with the key version. */ |
330 | *kernel_version = key_version << 16 | preamble->kernel_version; |
331 | |
332 | /* If not in recovery mode, check for rollback of the kernel version. */ |
333 | if (need_keyblock_valid && |
334 | ctx->boot_mode != VB2_BOOT_MODE_MANUAL_RECOVERY && |
335 | *kernel_version < sd->kernel_version_secdata) { |
336 | VB2_DEBUG("Kernel version too low.\n")vb2ex_printf(__func__, "Kernel version too low.\n"); |
337 | return VB2_ERROR_KERNEL_PREAMBLE_VERSION_ROLLBACK; |
338 | } |
339 | |
340 | VB2_DEBUG("Kernel preamble is good.\n")vb2ex_printf(__func__, "Kernel preamble is good.\n"); |
341 | return VB2_SUCCESS; |
342 | } |
343 | |
344 | /** |
345 | * Load and verify a partition from the stream. |
346 | * |
347 | * @param ctx Vboot context |
348 | * @param params Load-kernel parameters |
349 | * @param stream Stream to load kernel from |
350 | * @param lpflags Flags (one or more of vb2_load_partition_flags) |
351 | * @param kernel_version The kernel version of this partition. |
352 | * @return VB2_SUCCESS, or non-zero error code. |
353 | */ |
354 | static vb2_error_t vb2_load_partition(struct vb2_context *ctx, |
355 | struct vb2_kernel_params *params, |
356 | VbExStream_t stream, uint32_t lpflags, |
357 | uint32_t *kernel_version) |
358 | { |
359 | uint32_t read_ms = 0, start_ts; |
360 | struct vb2_workbuf wb; |
361 | |
362 | vb2_workbuf_from_ctx(ctx, &wb); |
363 | |
364 | /* Allocate kernel header buffer in workbuf */ |
365 | uint8_t *kbuf = vb2_workbuf_alloc(&wb, KBUF_SIZE65536); |
366 | if (!kbuf) |
367 | return VB2_ERROR_LOAD_PARTITION_WORKBUF; |
368 | |
369 | start_ts = vb2ex_mtime(); |
370 | if (VbExStreamRead(stream, KBUF_SIZE65536, kbuf)) { |
371 | VB2_DEBUG("Unable to read start of partition.\n")vb2ex_printf(__func__, "Unable to read start of partition.\n" ); |
372 | return VB2_ERROR_LOAD_PARTITION_READ_VBLOCK; |
373 | } |
374 | read_ms += vb2ex_mtime() - start_ts; |
375 | |
376 | if (vb2_verify_kernel_vblock(ctx, kbuf, KBUF_SIZE65536, lpflags, &wb, |
377 | kernel_version)) |
378 | return VB2_ERROR_LOAD_PARTITION_VERIFY_VBLOCK; |
379 | |
380 | if (lpflags & VB2_LOAD_PARTITION_FLAG_VBLOCK_ONLY) |
381 | return VB2_SUCCESS; |
382 | |
383 | struct vb2_keyblock *keyblock = get_keyblock(kbuf); |
384 | struct vb2_kernel_preamble *preamble = get_preamble(kbuf); |
385 | |
386 | /* |
387 | * Make sure the kernel starts at or before what we already read into |
388 | * kbuf. |
389 | * |
390 | * We could deal with a larger offset by reading and discarding the |
391 | * data in between the vblock and the kernel data. |
392 | */ |
393 | uint32_t body_offset = get_body_offset(kbuf); |
394 | if (body_offset > KBUF_SIZE65536) { |
395 | VB2_DEBUG("Kernel body offset is %u > 64KB.\n", body_offset)vb2ex_printf(__func__, "Kernel body offset is %u > 64KB.\n" , body_offset); |
396 | return VB2_ERROR_LOAD_PARTITION_BODY_OFFSET; |
397 | } |
398 | |
399 | uint8_t *kernbuf = params->kernel_buffer; |
400 | uint32_t kernbuf_size = params->kernel_buffer_size; |
401 | if (!kernbuf) { |
402 | /* Get kernel load address and size from the header. */ |
403 | kernbuf = (uint8_t *)((long)preamble->body_load_address); |
404 | kernbuf_size = preamble->body_signature.data_size; |
405 | } else if (preamble->body_signature.data_size > kernbuf_size) { |
406 | VB2_DEBUG("Kernel body doesn't fit in memory.\n")vb2ex_printf(__func__, "Kernel body doesn't fit in memory.\n" ); |
407 | return VB2_ERROR_LOAD_PARTITION_BODY_SIZE; |
408 | } |
409 | |
410 | uint32_t body_toread = preamble->body_signature.data_size; |
411 | uint8_t *body_readptr = kernbuf; |
412 | |
413 | /* |
414 | * If we've already read part of the kernel, copy that to the beginning |
415 | * of the kernel buffer. |
416 | */ |
417 | uint32_t body_copied = KBUF_SIZE65536 - body_offset; |
418 | if (body_copied > body_toread) |
419 | body_copied = body_toread; /* Don't over-copy tiny kernel */ |
420 | memcpy(body_readptr, kbuf + body_offset, body_copied); |
421 | body_toread -= body_copied; |
422 | body_readptr += body_copied; |
423 | |
424 | /* Read the kernel data */ |
425 | start_ts = vb2ex_mtime(); |
426 | if (body_toread && VbExStreamRead(stream, body_toread, body_readptr)) { |
427 | VB2_DEBUG("Unable to read kernel data.\n")vb2ex_printf(__func__, "Unable to read kernel data.\n"); |
428 | return VB2_ERROR_LOAD_PARTITION_READ_BODY; |
429 | } |
430 | read_ms += vb2ex_mtime() - start_ts; |
431 | if (read_ms == 0) /* Avoid division by 0 in speed calculation */ |
432 | read_ms = 1; |
433 | VB2_DEBUG("read %u KB in %u ms at %u KB/s.\n",vb2ex_printf(__func__, "read %u KB in %u ms at %u KB/s.\n", ( body_toread + 65536) / 1024, read_ms, (uint32_t)(((body_toread + 65536) * 1000ULL) / (read_ms * 1024))) |
434 | (body_toread + KBUF_SIZE) / 1024, read_ms,vb2ex_printf(__func__, "read %u KB in %u ms at %u KB/s.\n", ( body_toread + 65536) / 1024, read_ms, (uint32_t)(((body_toread + 65536) * 1000ULL) / (read_ms * 1024))) |
435 | (uint32_t)(((body_toread + KBUF_SIZE) * VB2_MSEC_PER_SEC) /vb2ex_printf(__func__, "read %u KB in %u ms at %u KB/s.\n", ( body_toread + 65536) / 1024, read_ms, (uint32_t)(((body_toread + 65536) * 1000ULL) / (read_ms * 1024))) |
436 | (read_ms * 1024)))vb2ex_printf(__func__, "read %u KB in %u ms at %u KB/s.\n", ( body_toread + 65536) / 1024, read_ms, (uint32_t)(((body_toread + 65536) * 1000ULL) / (read_ms * 1024))); |
437 | |
438 | /* Get key for preamble/data verification from the keyblock. */ |
439 | struct vb2_public_key data_key; |
440 | if (vb2_unpack_key(&data_key, &keyblock->data_key)) { |
441 | VB2_DEBUG("Unable to unpack kernel data key\n")vb2ex_printf(__func__, "Unable to unpack kernel data key\n"); |
442 | return VB2_ERROR_LOAD_PARTITION_DATA_KEY; |
443 | } |
444 | |
445 | data_key.allow_hwcrypto = vb2api_hwcrypto_allowed(ctx); |
446 | |
447 | /* Verify kernel data */ |
448 | if (vb2_verify_data(kernbuf, kernbuf_size, &preamble->body_signature, |
449 | &data_key, &wb)) { |
450 | VB2_DEBUG("Kernel data verification failed.\n")vb2ex_printf(__func__, "Kernel data verification failed.\n"); |
451 | return VB2_ERROR_LOAD_PARTITION_VERIFY_BODY; |
452 | } |
453 | |
454 | /* If we're still here, the kernel is valid */ |
455 | VB2_DEBUG("Partition is good.\n")vb2ex_printf(__func__, "Partition is good.\n"); |
456 | |
457 | /* Save kernel data back to parameters */ |
458 | params->bootloader_offset = preamble->bootloader_address - |
459 | preamble->body_load_address; |
460 | params->bootloader_size = preamble->bootloader_size; |
461 | params->flags = vb2_kernel_get_flags(preamble); |
462 | if (!params->kernel_buffer) { |
463 | params->kernel_buffer = kernbuf; |
464 | params->kernel_buffer_size = kernbuf_size; |
465 | } |
466 | |
467 | return VB2_SUCCESS; |
468 | } |
469 | |
470 | static vb2_error_t try_minios_kernel(struct vb2_context *ctx, |
471 | struct vb2_kernel_params *params, |
472 | struct vb2_disk_info *disk_info, |
473 | uint64_t sector) { |
474 | struct vb2_shared_data *sd = vb2_get_sd(ctx); |
475 | VbExStream_t stream; |
476 | uint64_t sectors_left = disk_info->lba_count - sector; |
477 | const uint32_t lpflags = VB2_LOAD_PARTITION_FLAG_MINIOS; |
478 | uint32_t kernel_version = 0; |
479 | vb2_error_t rv = VB2_ERROR_LK_NO_KERNEL_FOUND; |
480 | |
481 | /* Re-open stream at correct offset to pass to vb2_load_partition. */ |
482 | if (VbExStreamOpen(disk_info->handle, sector, sectors_left, |
483 | &stream)) { |
484 | VB2_DEBUG("Unable to open disk handle.\n")vb2ex_printf(__func__, "Unable to open disk handle.\n"); |
485 | return rv; |
486 | } |
487 | |
488 | rv = vb2_load_partition(ctx, params, stream, lpflags, &kernel_version); |
489 | VB2_DEBUG("vb2_load_partition returned: %d\n", rv)vb2ex_printf(__func__, "vb2_load_partition returned: %d\n", rv ); |
490 | |
491 | VbExStreamClose(stream); |
492 | |
493 | if (rv) |
494 | return VB2_ERROR_LK_NO_KERNEL_FOUND; |
495 | |
496 | sd->kernel_version = kernel_version; |
497 | |
498 | return rv; |
499 | } |
500 | |
501 | static vb2_error_t try_minios_sectors(struct vb2_context *ctx, |
502 | struct vb2_kernel_params *params, |
503 | struct vb2_disk_info *disk_info, |
504 | uint64_t start, uint64_t count) |
505 | { |
506 | const uint32_t buf_size = count * disk_info->bytes_per_lba; |
507 | char *buf; |
508 | VbExStream_t stream; |
509 | uint64_t isector; |
510 | vb2_error_t rv = VB2_ERROR_LK_NO_KERNEL_FOUND; |
511 | |
512 | buf = malloc(buf_size); |
513 | if (buf == NULL((void*)0)) { |
514 | VB2_DEBUG("Unable to allocate disk read buffer.\n")vb2ex_printf(__func__, "Unable to allocate disk read buffer.\n" ); |
515 | return rv; |
516 | } |
517 | |
518 | if (VbExStreamOpen(disk_info->handle, start, count, &stream)) { |
519 | VB2_DEBUG("Unable to open disk handle.\n")vb2ex_printf(__func__, "Unable to open disk handle.\n"); |
520 | free(buf); |
521 | return rv; |
522 | } |
523 | if (VbExStreamRead(stream, buf_size, buf)) { |
524 | VB2_DEBUG("Unable to read disk.\n")vb2ex_printf(__func__, "Unable to read disk.\n"); |
525 | free(buf); |
526 | VbExStreamClose(stream); |
527 | return rv; |
528 | } |
529 | VbExStreamClose(stream); |
530 | |
531 | for (isector = 0; isector < count; isector++) { |
532 | if (memcmp(buf + isector * disk_info->bytes_per_lba, |
533 | VB2_KEYBLOCK_MAGIC"CHROMEOS", VB2_KEYBLOCK_MAGIC_SIZE8)) |
534 | continue; |
535 | VB2_DEBUG("Match on sector %" PRIu64 " / %" PRIu64 "\n",vb2ex_printf(__func__, "Match on sector %" "l" "u" " / %" "l" "u" "\n", start + isector, disk_info->lba_count - 1) |
536 | start + isector,vb2ex_printf(__func__, "Match on sector %" "l" "u" " / %" "l" "u" "\n", start + isector, disk_info->lba_count - 1) |
537 | disk_info->lba_count - 1)vb2ex_printf(__func__, "Match on sector %" "l" "u" " / %" "l" "u" "\n", start + isector, disk_info->lba_count - 1); |
538 | rv = try_minios_kernel(ctx, params, disk_info, start + isector); |
539 | if (rv == VB2_SUCCESS) |
540 | break; |
541 | } |
542 | |
543 | free(buf); |
544 | return rv; |
545 | } |
546 | |
547 | static vb2_error_t try_minios_sector_region(struct vb2_context *ctx, |
548 | struct vb2_kernel_params *params, |
549 | struct vb2_disk_info *disk_info, |
550 | int end_region) |
551 | { |
552 | const uint64_t disk_count_half = (disk_info->lba_count + 1) / 2; |
553 | const uint64_t check_count_256 = 256 * 1024 |
554 | * 1024 / disk_info->bytes_per_lba; // 256 MB |
555 | const uint64_t batch_count_1 = 1024 |
556 | * 1024 / disk_info->bytes_per_lba; // 1 MB |
557 | const uint64_t check_count = VB2_MIN(disk_count_half, check_count_256)({ typeof(disk_count_half) __vb2_min_a = (disk_count_half); typeof (check_count_256) __vb2_min_b = (check_count_256); __vb2_min_a < __vb2_min_b ? __vb2_min_a : __vb2_min_b; }); |
558 | const uint64_t batch_count = VB2_MIN(disk_count_half, batch_count_1)({ typeof(disk_count_half) __vb2_min_a = (disk_count_half); typeof (batch_count_1) __vb2_min_b = (batch_count_1); __vb2_min_a < __vb2_min_b ? __vb2_min_a : __vb2_min_b; }); |
559 | uint64_t sector; |
560 | uint64_t start; |
561 | uint64_t end; |
562 | const char *region_name; |
563 | vb2_error_t rv = VB2_ERROR_LK_NO_KERNEL_FOUND; |
564 | |
565 | if (!end_region) { |
566 | start = 0; |
567 | end = check_count; |
568 | region_name = "start"; |
569 | } else { |
570 | start = disk_info->lba_count - check_count; |
571 | end = disk_info->lba_count; |
572 | region_name = "end"; |
573 | } |
574 | |
575 | VB2_DEBUG("Checking %s of disk for kernels...\n", region_name)vb2ex_printf(__func__, "Checking %s of disk for kernels...\n" , region_name); |
576 | for (sector = start; sector < end; sector += batch_count) { |
577 | rv = try_minios_sectors(ctx, params, disk_info, sector, |
578 | batch_count); |
579 | if (rv == VB2_SUCCESS) |
580 | return rv; |
581 | } |
582 | |
583 | return rv; |
584 | } |
585 | |
586 | /* |
587 | * Search for kernels by sector, rather than by partition. Only sectors near |
588 | * the start and end of disks are considered, and the kernel must start exactly |
589 | * at the first byte of the sector. |
590 | */ |
591 | vb2_error_t vb2api_load_minios_kernel(struct vb2_context *ctx, |
592 | struct vb2_kernel_params *params, |
593 | struct vb2_disk_info *disk_info, |
594 | uint32_t minios_flags) |
595 | { |
596 | vb2_error_t rv; |
597 | int end_region_first = vb2_nv_get(ctx, VB2_NV_MINIOS_PRIORITY); |
598 | |
599 | if (minios_flags & VB2_MINIOS_FLAG_NON_ACTIVE(1 << 0)) |
600 | rv = VB2_ERROR_UNKNOWN; /* Ignore active partition */ |
601 | else |
602 | rv = try_minios_sector_region(ctx, params, disk_info, |
603 | end_region_first); |
604 | |
605 | if (rv) |
606 | rv = try_minios_sector_region(ctx, params, disk_info, |
607 | !end_region_first); |
608 | |
609 | if (rv == VB2_SUCCESS) |
610 | params->disk_handle = disk_info->handle; |
611 | |
612 | return rv; |
613 | } |
614 | |
615 | vb2_error_t vb2api_load_kernel(struct vb2_context *ctx, |
616 | struct vb2_kernel_params *params, |
617 | struct vb2_disk_info *disk_info) |
618 | { |
619 | struct vb2_shared_data *sd = vb2_get_sd(ctx); |
620 | int found_partitions = 0; |
621 | uint32_t lowest_version = LOWEST_TPM_VERSION0xffffffff; |
622 | vb2_error_t rv; |
623 | |
624 | /* Clear output params */ |
625 | params->partition_number = 0; |
626 | |
627 | /* Read GPT data */ |
628 | GptData gpt; |
629 | gpt.sector_bytes = (uint32_t)disk_info->bytes_per_lba; |
630 | gpt.streaming_drive_sectors = disk_info->streaming_lba_count |
631 | ?: disk_info->lba_count; |
632 | gpt.gpt_drive_sectors = disk_info->lba_count; |
633 | gpt.flags = disk_info->flags & VB2_DISK_FLAG_EXTERNAL_GPT(1 << 16) |
634 | ? GPT_FLAG_EXTERNAL0x1 : 0; |
635 | if (AllocAndReadGptData(disk_info->handle, &gpt)) { |
636 | VB2_DEBUG("Unable to read GPT data\n")vb2ex_printf(__func__, "Unable to read GPT data\n"); |
637 | goto gpt_done; |
638 | } |
639 | |
640 | /* Initialize GPT library */ |
641 | if (GptInit(&gpt)) { |
642 | VB2_DEBUG("Error parsing GPT\n")vb2ex_printf(__func__, "Error parsing GPT\n"); |
643 | goto gpt_done; |
644 | } |
645 | |
646 | /* Loop over candidate kernel partitions */ |
647 | uint64_t part_start, part_size; |
648 | while (GptNextKernelEntry(&gpt, &part_start, &part_size) == |
649 | GPT_SUCCESS) { |
650 | |
651 | VB2_DEBUG("Found kernel entry at %"vb2ex_printf(__func__, "Found kernel entry at %" "l" "u" " size %" "l" "u" "\n", part_start, part_size) |
652 | PRIu64 " size %" PRIu64 "\n",vb2ex_printf(__func__, "Found kernel entry at %" "l" "u" " size %" "l" "u" "\n", part_start, part_size) |
653 | part_start, part_size)vb2ex_printf(__func__, "Found kernel entry at %" "l" "u" " size %" "l" "u" "\n", part_start, part_size); |
654 | |
655 | /* Found at least one kernel partition. */ |
656 | found_partitions++; |
657 | |
658 | /* Set up the stream */ |
659 | VbExStream_t stream = NULL((void*)0); |
660 | if (VbExStreamOpen(disk_info->handle, |
661 | part_start, part_size, &stream)) { |
662 | VB2_DEBUG("Partition error getting stream.\n")vb2ex_printf(__func__, "Partition error getting stream.\n"); |
663 | VB2_DEBUG("Marking kernel as invalid.\n")vb2ex_printf(__func__, "Marking kernel as invalid.\n"); |
664 | GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD); |
665 | continue; |
666 | } |
667 | |
668 | uint32_t lpflags = 0; |
669 | if (params->partition_number > 0) { |
670 | /* |
671 | * If we already have a good kernel, we only needed to |
672 | * look at the vblock versions to check for rollback. |
673 | */ |
674 | lpflags |= VB2_LOAD_PARTITION_FLAG_VBLOCK_ONLY; |
675 | } |
676 | |
677 | uint32_t kernel_version = 0; |
678 | rv = vb2_load_partition(ctx, params, stream, lpflags, |
679 | &kernel_version); |
680 | VbExStreamClose(stream); |
681 | |
682 | if (rv) { |
683 | VB2_DEBUG("Marking kernel as invalid (err=%x).\n", rv)vb2ex_printf(__func__, "Marking kernel as invalid (err=%x).\n" , rv); |
684 | GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD); |
685 | continue; |
686 | } |
687 | |
688 | int keyblock_valid = sd->flags & VB2_SD_FLAG_KERNEL_SIGNED; |
689 | /* Track lowest version from a valid header. */ |
690 | if (keyblock_valid && lowest_version > kernel_version) |
691 | lowest_version = kernel_version; |
692 | |
693 | VB2_DEBUG("Keyblock valid: %d\n", keyblock_valid)vb2ex_printf(__func__, "Keyblock valid: %d\n", keyblock_valid ); |
694 | VB2_DEBUG("Combined version: %u\n", kernel_version)vb2ex_printf(__func__, "Combined version: %u\n", kernel_version ); |
695 | |
696 | /* |
697 | * If we're only looking at headers, we're done with this |
698 | * partition. |
699 | */ |
700 | if (lpflags & VB2_LOAD_PARTITION_FLAG_VBLOCK_ONLY) |
701 | continue; |
702 | |
703 | /* |
704 | * Otherwise, we found a partition we like. |
705 | * |
706 | * TODO: GPT partitions start at 1, but cgptlib starts them at |
707 | * 0. Adjust here, until cgptlib is fixed. |
708 | */ |
709 | params->partition_number = gpt.current_kernel + 1; |
710 | |
711 | sd->kernel_version = kernel_version; |
712 | |
713 | /* |
714 | * TODO: GetCurrentKernelUniqueGuid() should take a destination |
715 | * size, or the dest should be a struct, so we know it's big |
716 | * enough. |
717 | */ |
718 | GetCurrentKernelUniqueGuid(&gpt, ¶ms->partition_guid); |
719 | |
720 | /* Update GPT to note this is the kernel we're trying. |
721 | * But not when we assume that the boot process may |
722 | * not complete for valid reasons (eg. early shutdown). |
723 | */ |
724 | if (!(ctx->flags & VB2_CONTEXT_NOFAIL_BOOT)) |
725 | GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_TRY); |
726 | |
727 | /* |
728 | * If we're in recovery mode or we're about to boot a |
729 | * non-officially-signed kernel, there's no rollback |
730 | * protection, so we can stop at the first valid kernel. |
731 | */ |
732 | if (ctx->boot_mode == VB2_BOOT_MODE_MANUAL_RECOVERY || |
733 | !keyblock_valid) { |
734 | VB2_DEBUG("In recovery mode or dev-signed kernel\n")vb2ex_printf(__func__, "In recovery mode or dev-signed kernel\n" ); |
735 | break; |
736 | } |
737 | |
738 | /* |
739 | * Otherwise, we do care about the key index in the TPM. If |
740 | * the good partition's key version is the same as the tpm, |
741 | * then the TPM doesn't need updating; we can stop now. |
742 | * Otherwise, we'll check all the other headers to see if they |
743 | * contain a newer key. |
744 | */ |
745 | if (sd->kernel_version == sd->kernel_version_secdata) { |
746 | VB2_DEBUG("Same kernel version\n")vb2ex_printf(__func__, "Same kernel version\n"); |
747 | break; |
748 | } |
749 | } /* while(GptNextKernelEntry) */ |
750 | |
751 | gpt_done: |
752 | /* Write and free GPT data */ |
753 | WriteAndFreeGptData(disk_info->handle, &gpt); |
754 | |
755 | /* Handle finding a good partition */ |
756 | if (params->partition_number > 0) { |
757 | VB2_DEBUG("Good partition %d\n", params->partition_number)vb2ex_printf(__func__, "Good partition %d\n", params->partition_number ); |
758 | /* |
759 | * Validity check - only store a new TPM version if we found |
760 | * one. If lowest_version is still at its initial value, we |
761 | * didn't find one; for example, we're in developer mode and |
762 | * just didn't look. |
763 | */ |
764 | if (lowest_version != LOWEST_TPM_VERSION0xffffffff && |
765 | lowest_version > sd->kernel_version_secdata) |
766 | sd->kernel_version_secdata = lowest_version; |
767 | |
768 | /* Success! */ |
769 | rv = VB2_SUCCESS; |
770 | params->disk_handle = disk_info->handle; |
771 | } else if (found_partitions > 0) { |
772 | rv = VB2_ERROR_LK_INVALID_KERNEL_FOUND; |
773 | } else { |
774 | rv = VB2_ERROR_LK_NO_KERNEL_FOUND; |
775 | } |
776 | |
777 | return rv; |
778 | } |