Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1689)

Side by Side Diff: firmware/lib/vboot_kernel.c

Issue 3130040: Fix LoadKernel() failing to update GPT flags. (Closed) Base URL: ssh://gitrw.chromium.org/vboot_reference.git
Patch Set: Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | firmware/version.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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, &params->partition_guid); 347 GetCurrentKernelUniqueGuid(&gpt, &params->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
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 }
OLDNEW
« no previous file with comments | « no previous file | firmware/version.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698