OLD | NEW |
---|---|
1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 * Use of this source code is governed by a BSD-style license that can be | 2 * Use of this source code is governed by a BSD-style license that can be |
3 * found in the LICENSE file. | 3 * found in the LICENSE file. |
4 * | 4 * |
5 * Functions for loading a kernel from disk. | 5 * Functions for loading a kernel from disk. |
6 * (Firmware portion) | 6 * (Firmware portion) |
7 */ | 7 */ |
8 | 8 |
9 #include "vboot_kernel.h" | 9 #include "vboot_kernel.h" |
10 | 10 |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
192 | 192 |
193 /* Allocate kernel header buffers */ | 193 /* Allocate kernel header buffers */ |
194 kbuf = (uint8_t*)Malloc(KBUF_SIZE); | 194 kbuf = (uint8_t*)Malloc(KBUF_SIZE); |
195 if (!kbuf) | 195 if (!kbuf) |
196 break; | 196 break; |
197 | 197 |
198 /* Loop over candidate kernel partitions */ | 198 /* Loop over candidate kernel partitions */ |
199 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { | 199 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { |
200 VbKeyBlockHeader* key_block; | 200 VbKeyBlockHeader* key_block; |
201 VbKernelPreambleHeader* preamble; | 201 VbKernelPreambleHeader* preamble; |
202 RSAPublicKey* data_key; | 202 RSAPublicKey* data_key = NULL; |
203 uint64_t key_version; | 203 uint64_t key_version; |
204 uint64_t combined_version; | 204 uint64_t combined_version; |
205 uint64_t body_offset; | 205 uint64_t body_offset; |
206 uint64_t body_offset_sectors; | 206 uint64_t body_offset_sectors; |
207 uint64_t body_sectors; | 207 uint64_t body_sectors; |
208 | 208 |
209 VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", | 209 VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", |
210 part_start, part_size)); | 210 part_start, part_size)); |
211 | 211 |
212 /* Found at least one kernel partition. */ | 212 /* Found at least one kernel partition. */ |
213 found_partitions++; | 213 found_partitions++; |
214 | 214 |
215 /* Read the first part of the kernel partition */ | 215 /* Read the first part of the kernel partition */ |
216 if (part_size < kbuf_sectors) | 216 if (part_size < kbuf_sectors) |
217 continue; | 217 goto bad_kernel; |
218 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) | 218 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) |
219 continue; | 219 goto bad_kernel; |
220 | 220 |
221 /* Verify the key block. In developer mode, we ignore the key | 221 /* Verify the key block. In developer mode, we ignore the key |
222 * and use only the SHA-512 hash to verify the key block. */ | 222 * and use only the SHA-512 hash to verify the key block. */ |
223 key_block = (VbKeyBlockHeader*)kbuf; | 223 key_block = (VbKeyBlockHeader*)kbuf; |
224 if ((0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, | 224 if ((0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, |
225 is_dev && !is_rec))) { | 225 is_dev && !is_rec))) { |
226 VBDEBUG(("Verifying key block failed.\n")); | 226 VBDEBUG(("Verifying key block failed.\n")); |
227 continue; | 227 goto bad_kernel; |
228 } | 228 } |
229 | 229 |
230 /* Check the key block flags against the current boot mode in normal | 230 /* Check the key block flags against the current boot mode in normal |
231 * and recovery modes (not in developer mode booting from SSD). */ | 231 * and recovery modes (not in developer mode booting from SSD). */ |
232 if (is_rec || is_normal) { | 232 if (is_rec || is_normal) { |
233 if (!(key_block->key_block_flags & | 233 if (!(key_block->key_block_flags & |
234 (is_dev ? KEY_BLOCK_FLAG_DEVELOPER_1 : | 234 (is_dev ? KEY_BLOCK_FLAG_DEVELOPER_1 : |
235 KEY_BLOCK_FLAG_DEVELOPER_0))) { | 235 KEY_BLOCK_FLAG_DEVELOPER_0))) { |
236 VBDEBUG(("Developer flag mismatch.\n")); | 236 VBDEBUG(("Developer flag mismatch.\n")); |
237 continue; | 237 goto bad_kernel; |
238 } | 238 } |
239 if (!(key_block->key_block_flags & | 239 if (!(key_block->key_block_flags & |
240 (is_rec ? KEY_BLOCK_FLAG_RECOVERY_1 : | 240 (is_rec ? KEY_BLOCK_FLAG_RECOVERY_1 : |
241 KEY_BLOCK_FLAG_RECOVERY_0))) { | 241 KEY_BLOCK_FLAG_RECOVERY_0))) { |
242 VBDEBUG(("Recovery flag mismatch.\n")); | 242 VBDEBUG(("Recovery flag mismatch.\n")); |
243 continue; | 243 goto bad_kernel; |
244 } | 244 } |
245 } | 245 } |
246 | 246 |
247 /* Check for rollback of key version. Note this is implicitly | 247 /* Check for rollback of key version. Note this is implicitly |
248 * skipped in recovery and developer modes because those set | 248 * skipped in recovery and developer modes because those set |
249 * key_version=0 above. */ | 249 * key_version=0 above. */ |
250 key_version = key_block->data_key.key_version; | 250 key_version = key_block->data_key.key_version; |
251 if (key_version < (tpm_version >> 16)) { | 251 if (key_version < (tpm_version >> 16)) { |
252 VBDEBUG(("Key version too old.\n")); | 252 VBDEBUG(("Key version too old.\n")); |
253 continue; | 253 goto bad_kernel; |
254 } | 254 } |
255 | 255 |
256 /* Get the key for preamble/data verification from the key block */ | 256 /* Get the key for preamble/data verification from the key block */ |
257 data_key = PublicKeyToRSA(&key_block->data_key); | 257 data_key = PublicKeyToRSA(&key_block->data_key); |
258 if (!data_key) | 258 if (!data_key) |
259 continue; | 259 goto bad_kernel; |
260 | 260 |
261 /* Verify the preamble, which follows the key block */ | 261 /* Verify the preamble, which follows the key block */ |
262 preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); | 262 preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); |
263 if ((0 != VerifyKernelPreamble(preamble, | 263 if ((0 != VerifyKernelPreamble(preamble, |
264 KBUF_SIZE - key_block->key_block_size, | 264 KBUF_SIZE - key_block->key_block_size, |
265 data_key))) { | 265 data_key))) { |
266 VBDEBUG(("Preamble verification failed.\n")); | 266 VBDEBUG(("Preamble verification failed.\n")); |
267 RSAPublicKeyFree(data_key); | 267 goto bad_kernel; |
268 continue; | |
269 } | 268 } |
270 | 269 |
271 /* Check for rollback of kernel version. Note this is implicitly | 270 /* Check for rollback of kernel version. Note this is implicitly |
272 * skipped in recovery and developer modes because rollback_index | 271 * skipped in recovery and developer modes because rollback_index |
273 * sets those to 0 in those modes. */ | 272 * sets those to 0 in those modes. */ |
274 combined_version = ((key_version << 16) | | 273 combined_version = ((key_version << 16) | |
275 (preamble->kernel_version & 0xFFFF)); | 274 (preamble->kernel_version & 0xFFFF)); |
276 if (combined_version < tpm_version) { | 275 if (combined_version < tpm_version) { |
277 VBDEBUG(("Kernel version too low.\n")); | 276 VBDEBUG(("Kernel version too low.\n")); |
278 RSAPublicKeyFree(data_key); | 277 goto bad_kernel; |
279 continue; | |
280 } | 278 } |
281 | 279 |
282 VBDEBUG(("Kernel preamble is good.\n")); | 280 VBDEBUG(("Kernel preamble is good.\n")); |
283 | 281 |
284 /* Check for lowest version from a valid header. */ | 282 /* Check for lowest version from a valid header. */ |
285 if (lowest_version > combined_version) | 283 if (lowest_version > combined_version) |
286 lowest_version = combined_version; | 284 lowest_version = combined_version; |
287 | 285 |
288 /* If we already have a good kernel, no need to read another | 286 /* If we already have a good kernel, no need to read another |
289 * one; we only needed to look at the versions to check for | 287 * one; we only needed to look at the versions to check for |
290 * rollback. */ | 288 * rollback. */ |
291 if (-1 != good_partition) | 289 if (-1 != good_partition) |
292 continue; | 290 goto bad_kernel; |
Randall Spangler
2010/08/20 21:20:47
Heh, note that we'd previously missed freeing the
| |
293 | 291 |
294 /* Verify body load address matches what we expect */ | 292 /* Verify body load address matches what we expect */ |
295 if ((preamble->body_load_address != (size_t)params->kernel_buffer) && | 293 if ((preamble->body_load_address != (size_t)params->kernel_buffer) && |
296 !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) { | 294 !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) { |
297 VBDEBUG(("Wrong body load address.\n")); | 295 VBDEBUG(("Wrong body load address.\n")); |
298 RSAPublicKeyFree(data_key); | 296 goto bad_kernel; |
299 continue; | |
300 } | 297 } |
301 | 298 |
302 /* Verify kernel body starts at a multiple of the sector size. */ | 299 /* Verify kernel body starts at a multiple of the sector size. */ |
303 body_offset = key_block->key_block_size + preamble->preamble_size; | 300 body_offset = key_block->key_block_size + preamble->preamble_size; |
304 if (0 != body_offset % blba) { | 301 if (0 != body_offset % blba) { |
305 VBDEBUG(("Kernel body not at multiple of sector size.\n")); | 302 VBDEBUG(("Kernel body not at multiple of sector size.\n")); |
306 RSAPublicKeyFree(data_key); | 303 goto bad_kernel; |
307 continue; | |
308 } | 304 } |
309 body_offset_sectors = body_offset / blba; | 305 body_offset_sectors = body_offset / blba; |
310 | 306 |
311 /* Verify kernel body fits in the buffer */ | 307 /* Verify kernel body fits in the buffer */ |
312 body_sectors = (preamble->body_signature.data_size + blba - 1) / blba; | 308 body_sectors = (preamble->body_signature.data_size + blba - 1) / blba; |
313 if (body_sectors * blba > params->kernel_buffer_size) { | 309 if (body_sectors * blba > params->kernel_buffer_size) { |
314 VBDEBUG(("Kernel body doesn't fit in memory.\n")); | 310 VBDEBUG(("Kernel body doesn't fit in memory.\n")); |
315 RSAPublicKeyFree(data_key); | 311 goto bad_kernel; |
316 continue; | |
317 } | 312 } |
318 | 313 |
319 /* Verify kernel body fits in the partition */ | 314 /* Verify kernel body fits in the partition */ |
320 if (body_offset_sectors + body_sectors > part_size) { | 315 if (body_offset_sectors + body_sectors > part_size) { |
321 VBDEBUG(("Kernel body doesn't fit in partition.\n")); | 316 VBDEBUG(("Kernel body doesn't fit in partition.\n")); |
322 RSAPublicKeyFree(data_key); | 317 goto bad_kernel; |
323 continue; | |
324 } | 318 } |
325 | 319 |
326 /* Read the kernel data */ | 320 /* Read the kernel data */ |
327 if (0 != BootDeviceReadLBA(part_start + body_offset_sectors, | 321 if (0 != BootDeviceReadLBA(part_start + body_offset_sectors, |
328 body_sectors, | 322 body_sectors, |
329 params->kernel_buffer)) { | 323 params->kernel_buffer)) { |
330 VBDEBUG(("Unable to read kernel data.\n")); | 324 VBDEBUG(("Unable to read kernel data.\n")); |
331 RSAPublicKeyFree(data_key); | 325 goto bad_kernel; |
332 continue; | |
333 } | 326 } |
334 | 327 |
335 /* Verify kernel data */ | 328 /* Verify kernel data */ |
336 if (0 != VerifyData((const uint8_t*)params->kernel_buffer, | 329 if (0 != VerifyData((const uint8_t*)params->kernel_buffer, |
337 params->kernel_buffer_size, | 330 params->kernel_buffer_size, |
338 &preamble->body_signature, data_key)) { | 331 &preamble->body_signature, data_key)) { |
339 VBDEBUG(("Kernel data verification failed.\n")); | 332 VBDEBUG(("Kernel data verification failed.\n")); |
340 RSAPublicKeyFree(data_key); | 333 goto bad_kernel; |
341 continue; | |
342 } | 334 } |
343 | 335 |
344 /* Done with the kernel signing key, so can free it now */ | 336 /* Done with the kernel signing key, so can free it now */ |
345 RSAPublicKeyFree(data_key); | 337 RSAPublicKeyFree(data_key); |
338 data_key = NULL; | |
346 | 339 |
347 /* If we're still here, the kernel is valid. */ | 340 /* If we're still here, the kernel is valid. */ |
348 /* Save the first good partition we find; that's the one we'll boot */ | 341 /* Save the first good partition we find; that's the one we'll boot */ |
349 VBDEBUG(("Partiton is good.\n")); | 342 VBDEBUG(("Partiton is good.\n")); |
350 /* TODO: GPT partitions start at 1, but cgptlib starts them at 0. | 343 /* TODO: GPT partitions start at 1, but cgptlib starts them at 0. |
351 * Adjust here, until cgptlib is fixed. */ | 344 * Adjust here, until cgptlib is fixed. */ |
352 good_partition = gpt.current_kernel + 1; | 345 good_partition = gpt.current_kernel + 1; |
353 params->partition_number = gpt.current_kernel + 1; | 346 params->partition_number = gpt.current_kernel + 1; |
354 GetCurrentKernelUniqueGuid(&gpt, ¶ms->partition_guid); | 347 GetCurrentKernelUniqueGuid(&gpt, ¶ms->partition_guid); |
355 /* TODO: GetCurrentKernelUniqueGuid() should take a destination size, or | 348 /* TODO: GetCurrentKernelUniqueGuid() should take a destination size, or |
356 * the dest should be a struct, so we know it's big enough. */ | 349 * the dest should be a struct, so we know it's big enough. */ |
357 params->bootloader_address = preamble->bootloader_address; | 350 params->bootloader_address = preamble->bootloader_address; |
358 params->bootloader_size = preamble->bootloader_size; | 351 params->bootloader_size = preamble->bootloader_size; |
352 | |
353 /* Update GPT to note this is the kernel we're trying */ | |
354 GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_TRY); | |
355 | |
359 /* If we're in developer or recovery mode, there's no rollback | 356 /* If we're in developer or recovery mode, there's no rollback |
360 * protection, so we can stop at the first valid kernel. */ | 357 * protection, so we can stop at the first valid kernel. */ |
361 if (!is_normal) { | 358 if (!is_normal) { |
362 VBDEBUG(("Boot_flags = !is_normal\n")); | 359 VBDEBUG(("Boot_flags = !is_normal\n")); |
363 break; | 360 break; |
364 } | 361 } |
365 | 362 |
366 /* Otherwise, we're in normal boot mode, so we do care about the | 363 /* Otherwise, we're in normal boot mode, so we do care about the |
367 * key index in the TPM. If the good partition's key version is | 364 * key index in the TPM. If the good partition's key version is |
368 * the same as the tpm, then the TPM doesn't need updating; we | 365 * the same as the tpm, then the TPM doesn't need updating; we |
369 * can stop now. Otherwise, we'll check all the other headers | 366 * can stop now. Otherwise, we'll check all the other headers |
370 * to see if they contain a newer key. */ | 367 * to see if they contain a newer key. */ |
371 if (combined_version == tpm_version) { | 368 if (combined_version == tpm_version) { |
372 VBDEBUG(("Same kernel version\n")); | 369 VBDEBUG(("Same kernel version\n")); |
373 break; | 370 break; |
374 } | 371 } |
372 | |
373 /* Continue, so that we skip the error handling code below */ | |
374 continue; | |
375 | |
376 bad_kernel: | |
377 /* Handle errors parsing this kernel */ | |
378 if (NULL != data_key) | |
gauravsh
2010/08/20 21:29:01
this null check is not needed. All the *Free() fun
| |
379 RSAPublicKeyFree(data_key); | |
380 | |
381 VBDEBUG(("Marking kernel as invalid.\n")); | |
382 GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD); | |
383 | |
384 | |
375 } /* while(GptNextKernelEntry) */ | 385 } /* while(GptNextKernelEntry) */ |
376 } while(0); | 386 } while(0); |
377 | 387 |
378 /* Free kernel buffer */ | 388 /* Free kernel buffer */ |
379 if (kbuf) | 389 if (kbuf) |
380 Free(kbuf); | 390 Free(kbuf); |
381 | 391 |
382 /* Write and free GPT data */ | 392 /* Write and free GPT data */ |
383 WriteAndFreeGptData(&gpt); | 393 WriteAndFreeGptData(&gpt); |
384 | 394 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
418 /* Success! */ | 428 /* Success! */ |
419 return LOAD_KERNEL_SUCCESS; | 429 return LOAD_KERNEL_SUCCESS; |
420 } | 430 } |
421 | 431 |
422 // Handle error cases | 432 // Handle error cases |
423 if (found_partitions) | 433 if (found_partitions) |
424 return LOAD_KERNEL_INVALID; | 434 return LOAD_KERNEL_INVALID; |
425 else | 435 else |
426 return LOAD_KERNEL_NOT_FOUND; | 436 return LOAD_KERNEL_NOT_FOUND; |
427 } | 437 } |
OLD | NEW |