vboot_kernel.c revision ad6824ba4fc18c4eba4e98ba2b2e476dfcedbbae
1/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
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 "vboot_kernel.h"
10
11#include "boot_device.h"
12#include "cgptlib.h"
13#include "cgptlib_internal.h"
14#include "gbb_header.h"
15#include "load_kernel_fw.h"
16#include "rollback_index.h"
17#include "utility.h"
18#include "vboot_common.h"
19
20#define KBUF_SIZE 65536  /* Bytes to read at start of kernel partition */
21#define LOWEST_TPM_VERSION 0xffffffff
22
23typedef enum BootMode {
24  kBootNormal,   /* Normal firmware */
25  kBootDev,      /* Dev firmware AND dev switch is on */
26  kBootRecovery  /* Recovery firmware, regardless of dev switch position */
27} BootMode;
28
29
30/* Allocates and reads GPT data from the drive.  The sector_bytes and
31 * drive_sectors fields should be filled on input.  The primary and
32 * secondary header and entries are filled on output.
33 *
34 * Returns 0 if successful, 1 if error. */
35int AllocAndReadGptData(GptData* gptdata) {
36
37  uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes;
38
39  /* No data to be written yet */
40  gptdata->modified = 0;
41
42  /* Allocate all buffers */
43  gptdata->primary_header = (uint8_t*)Malloc(gptdata->sector_bytes);
44  gptdata->secondary_header = (uint8_t*)Malloc(gptdata->sector_bytes);
45  gptdata->primary_entries = (uint8_t*)Malloc(TOTAL_ENTRIES_SIZE);
46  gptdata->secondary_entries = (uint8_t*)Malloc(TOTAL_ENTRIES_SIZE);
47
48  if (gptdata->primary_header == NULL || gptdata->secondary_header == NULL ||
49      gptdata->primary_entries == NULL || gptdata->secondary_entries == NULL)
50    return 1;
51
52  /* Read data from the drive, skipping the protective MBR */
53  if (0 != BootDeviceReadLBA(1, 1, gptdata->primary_header))
54    return 1;
55  if (0 != BootDeviceReadLBA(2, entries_sectors, gptdata->primary_entries))
56    return 1;
57  if (0 != BootDeviceReadLBA(gptdata->drive_sectors - entries_sectors - 1,
58                             entries_sectors, gptdata->secondary_entries))
59    return 1;
60  if (0 != BootDeviceReadLBA(gptdata->drive_sectors - 1,
61                             1, gptdata->secondary_header))
62    return 1;
63
64  return 0;
65}
66
67
68/* Writes any changes for the GPT data back to the drive, then frees
69 * the buffers.
70 *
71 * Returns 0 if successful, 1 if error. */
72int WriteAndFreeGptData(GptData* gptdata) {
73
74  uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes;
75
76  if (gptdata->primary_header) {
77    if (gptdata->modified & GPT_MODIFIED_HEADER1) {
78      VBDEBUG(("Updating GPT header 1\n"));
79      if (0 != BootDeviceWriteLBA(1, 1, gptdata->primary_header))
80        return 1;
81    }
82    Free(gptdata->primary_header);
83  }
84
85  if (gptdata->primary_entries) {
86    if (gptdata->modified & GPT_MODIFIED_ENTRIES1) {
87      VBDEBUG(("Updating GPT entries 1\n"));
88      if (0 != BootDeviceWriteLBA(2, entries_sectors,
89                                  gptdata->primary_entries))
90        return 1;
91    }
92    Free(gptdata->primary_entries);
93  }
94
95  if (gptdata->secondary_entries) {
96    if (gptdata->modified & GPT_MODIFIED_ENTRIES2) {
97      VBDEBUG(("Updating GPT header 2\n"));
98      if (0 != BootDeviceWriteLBA(gptdata->drive_sectors - entries_sectors - 1,
99                                  entries_sectors, gptdata->secondary_entries))
100        return 1;
101    }
102    Free(gptdata->secondary_entries);
103  }
104
105  if (gptdata->secondary_header) {
106    if (gptdata->modified & GPT_MODIFIED_HEADER2) {
107      VBDEBUG(("Updating GPT entries 2\n"));
108      if (0 != BootDeviceWriteLBA(gptdata->drive_sectors - 1, 1,
109                                  gptdata->secondary_header))
110        return 1;
111    }
112    Free(gptdata->secondary_header);
113  }
114
115  /* Success */
116  return 0;
117}
118
119/* disable MSVC warning on const logical expression (as in } while(0);) */
120__pragma(warning(disable: 4127))
121
122int LoadKernel(LoadKernelParams* params) {
123  VbSharedDataHeader* shared = (VbSharedDataHeader*)params->shared_data_blob;
124  VbNvContext* vnc = params->nv_context;
125  GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)params->gbb_data;
126  VbPublicKey* kernel_subkey;
127  GptData gpt;
128  uint64_t part_start, part_size;
129  uint64_t blba;
130  uint64_t kbuf_sectors;
131  uint8_t* kbuf = NULL;
132  int found_partitions = 0;
133  int good_partition = -1;
134  int good_partition_key_block_valid = 0;
135  uint32_t tpm_version = 0;
136  uint64_t lowest_version = LOWEST_TPM_VERSION;
137  int rec_switch, dev_switch;
138  BootMode boot_mode;
139  uint32_t test_err = 0;
140  uint32_t status;
141
142  int retval = LOAD_KERNEL_RECOVERY;
143  int recovery = VBNV_RECOVERY_RO_UNSPECIFIED;
144  uint64_t timer_enter = VbGetTimer();
145
146  /* Setup NV storage */
147  VbNvSetup(vnc);
148
149  /* Sanity Checks */
150  if (!params ||
151      !params->bytes_per_lba ||
152      !params->ending_lba ||
153      !params->kernel_buffer ||
154      !params->kernel_buffer_size) {
155    VBDEBUG(("LoadKernel() called with invalid params\n"));
156    goto LoadKernelExit;
157  }
158
159  /* Clear output params in case we fail */
160  params->partition_number = 0;
161  params->bootloader_address = 0;
162  params->bootloader_size = 0;
163
164  /* Handle test errors */
165  VbNvGet(vnc, VBNV_TEST_ERROR_FUNC, &test_err);
166  if (VBNV_TEST_ERROR_LOAD_KERNEL == test_err) {
167    /* Get error code */
168    VbNvGet(vnc, VBNV_TEST_ERROR_NUM, &test_err);
169    /* Clear test params so we don't repeat the error */
170    VbNvSet(vnc, VBNV_TEST_ERROR_FUNC, 0);
171    VbNvSet(vnc, VBNV_TEST_ERROR_NUM, 0);
172    /* Handle error codes */
173    switch (test_err) {
174      case LOAD_KERNEL_RECOVERY:
175        recovery = VBNV_RECOVERY_RW_TEST_LK;
176        goto LoadKernelExit;
177      case LOAD_KERNEL_NOT_FOUND:
178      case LOAD_KERNEL_INVALID:
179      case LOAD_KERNEL_REBOOT:
180        retval = test_err;
181        goto LoadKernelExit;
182      default:
183        break;
184    }
185  }
186
187  /* Initialization */
188  blba = params->bytes_per_lba;
189  kbuf_sectors = KBUF_SIZE / blba;
190  if (0 == kbuf_sectors) {
191    VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n"));
192    goto LoadKernelExit;
193  }
194
195  rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0);
196  dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0);
197
198  if (rec_switch)
199    boot_mode = kBootRecovery;
200  else if (BOOT_FLAG_DEV_FIRMWARE & params->boot_flags) {
201    if (!dev_switch) {
202      /* Dev firmware should be signed such that it never boots with the dev
203       * switch is off; so something is terribly wrong. */
204      VBDEBUG(("LoadKernel() called with dev firmware but dev switch off\n"));
205      recovery = VBNV_RECOVERY_RW_DEV_MISMATCH;
206      goto LoadKernelExit;
207    }
208    boot_mode = kBootDev;
209  } else {
210    /* Normal firmware */
211    boot_mode = kBootNormal;
212    dev_switch = 0;  /* Always do a fully verified boot */
213  }
214
215  if (kBootRecovery == boot_mode) {
216    /* Initialize the shared data structure, since LoadFirmware() didn't do it
217     * for us. */
218    if (0 != VbSharedDataInit(shared, params->shared_data_size)) {
219      /* Error initializing the shared data, but we can keep going.  We just
220       * can't use the shared data. */
221      VBDEBUG(("Shared data init error\n"));
222      params->shared_data_size = 0;
223      shared = NULL;
224    }
225
226    /* Use the recovery key to verify the kernel */
227    kernel_subkey = (VbPublicKey*)((uint8_t*)gbb + gbb->recovery_key_offset);
228
229    /* Let the TPM know if we're in recovery mode */
230    if (0 != RollbackKernelRecovery(dev_switch)) {
231      VBDEBUG(("Error setting up TPM for recovery kernel\n"));
232      /* Ignore return code, since we need to boot recovery mode to
233       * fix the TPM. */
234    }
235  } else {
236    /* Use the kernel subkey passed from LoadFirmware(). */
237    kernel_subkey = &shared->kernel_subkey;
238
239    /* Read current kernel key index from TPM.  Assumes TPM is already
240     * initialized. */
241    status = RollbackKernelRead(&tpm_version);
242    if (0 != status) {
243      VBDEBUG(("Unable to get kernel versions from TPM\n"));
244      if (status == TPM_E_MUST_REBOOT)
245        retval = LOAD_KERNEL_REBOOT;
246      else
247        recovery = VBNV_RECOVERY_RW_TPM_ERROR;
248      goto LoadKernelExit;
249    }
250  }
251
252  do {
253    /* Read GPT data */
254    gpt.sector_bytes = (uint32_t)blba;
255    gpt.drive_sectors = params->ending_lba + 1;
256    if (0 != AllocAndReadGptData(&gpt)) {
257      VBDEBUG(("Unable to read GPT data\n"));
258      break;
259    }
260
261    /* Initialize GPT library */
262    if (GPT_SUCCESS != GptInit(&gpt)) {
263      VBDEBUG(("Error parsing GPT\n"));
264      break;
265    }
266
267    /* Allocate kernel header buffers */
268    kbuf = (uint8_t*)Malloc(KBUF_SIZE);
269    if (!kbuf)
270      break;
271
272    /* Loop over candidate kernel partitions */
273    while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) {
274      VbKeyBlockHeader* key_block;
275      VbKernelPreambleHeader* preamble;
276      RSAPublicKey* data_key = NULL;
277      uint64_t key_version;
278      uint64_t combined_version;
279      uint64_t body_offset;
280      uint64_t body_offset_sectors;
281      uint64_t body_sectors;
282      int key_block_valid = 1;
283
284      VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n",
285              part_start, part_size));
286
287      /* Found at least one kernel partition. */
288      found_partitions++;
289
290      /* Read the first part of the kernel partition. */
291      if (part_size < kbuf_sectors) {
292        VBDEBUG(("Partition too small to hold kernel.\n"));
293        goto bad_kernel;
294      }
295
296      if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) {
297        VBDEBUG(("Unable to read start of partition.\n"));
298        goto bad_kernel;
299      }
300
301      /* Verify the key block. */
302      key_block = (VbKeyBlockHeader*)kbuf;
303      if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 0)) {
304        VBDEBUG(("Verifying key block signature failed.\n"));
305        key_block_valid = 0;
306
307        /* If we're not in developer mode, this kernel is bad. */
308        if (kBootDev != boot_mode)
309          goto bad_kernel;
310
311        /* In developer mode, we can continue if the SHA-512 hash of the key
312         * block is valid. */
313        if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) {
314          VBDEBUG(("Verifying key block hash failed.\n"));
315          goto bad_kernel;
316        }
317      }
318
319      /* Check the key block flags against the current boot mode. */
320      if (!(key_block->key_block_flags &
321            (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 :
322             KEY_BLOCK_FLAG_DEVELOPER_0))) {
323        VBDEBUG(("Key block developer flag mismatch.\n"));
324        key_block_valid = 0;
325      }
326      if (!(key_block->key_block_flags &
327            (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 :
328             KEY_BLOCK_FLAG_RECOVERY_0))) {
329        VBDEBUG(("Key block recovery flag mismatch.\n"));
330        key_block_valid = 0;
331      }
332
333      /* Check for rollback of key version except in recovery mode. */
334      key_version = key_block->data_key.key_version;
335      if (kBootRecovery != boot_mode) {
336        if (key_version < (tpm_version >> 16)) {
337          VBDEBUG(("Key version too old.\n"));
338          key_block_valid = 0;
339        }
340      }
341
342      /* If we're not in developer mode, require the key block to be valid. */
343      if (kBootDev != boot_mode && !key_block_valid) {
344        VBDEBUG(("Key block is invalid.\n"));
345        goto bad_kernel;
346      }
347
348      /* Get the key for preamble/data verification from the key block. */
349      data_key = PublicKeyToRSA(&key_block->data_key);
350      if (!data_key) {
351        VBDEBUG(("Data key bad.\n"));
352        goto bad_kernel;
353      }
354
355      /* Verify the preamble, which follows the key block */
356      preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size);
357      if ((0 != VerifyKernelPreamble(preamble,
358                                     KBUF_SIZE - key_block->key_block_size,
359                                     data_key))) {
360        VBDEBUG(("Preamble verification failed.\n"));
361        goto bad_kernel;
362      }
363
364      /* If the key block is valid and we're not in recovery mode, check for
365       * rollback of the kernel version. */
366      combined_version = ((key_version << 16) |
367                          (preamble->kernel_version & 0xFFFF));
368      if (key_block_valid && kBootRecovery != boot_mode) {
369        if (combined_version < tpm_version) {
370          VBDEBUG(("Kernel version too low.\n"));
371          /* If we're not in developer mode, kernel version must be valid. */
372          if (kBootDev != boot_mode)
373            goto bad_kernel;
374        }
375      }
376
377      VBDEBUG(("Kernel preamble is good.\n"));
378
379      /* Check for lowest version from a valid header. */
380      if (key_block_valid && lowest_version > combined_version)
381        lowest_version = combined_version;
382      else {
383        VBDEBUG(("Key block valid: %d\n", key_block_valid));
384        VBDEBUG(("Combined version: %" PRIu64 "\n", combined_version));
385      }
386
387      /* If we already have a good kernel, no need to read another
388       * one; we only needed to look at the versions to check for
389       * rollback.  So skip to the next kernel preamble. */
390      if (-1 != good_partition)
391        continue;
392
393      /* Verify body load address matches what we expect */
394      if ((preamble->body_load_address != (size_t)params->kernel_buffer) &&
395          !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) {
396        VBDEBUG(("Wrong body load address.\n"));
397        goto bad_kernel;
398      }
399
400      /* Verify kernel body starts at a multiple of the sector size. */
401      body_offset = key_block->key_block_size + preamble->preamble_size;
402      if (0 != body_offset % blba) {
403        VBDEBUG(("Kernel body not at multiple of sector size.\n"));
404        goto bad_kernel;
405      }
406      body_offset_sectors = body_offset / blba;
407
408      /* Verify kernel body fits in the buffer */
409      body_sectors = (preamble->body_signature.data_size + blba - 1) / blba;
410      if (body_sectors * blba > params->kernel_buffer_size) {
411        VBDEBUG(("Kernel body doesn't fit in memory.\n"));
412        goto bad_kernel;
413      }
414
415      /* Verify kernel body fits in the partition */
416      if (body_offset_sectors + body_sectors > part_size) {
417        VBDEBUG(("Kernel body doesn't fit in partition.\n"));
418        goto bad_kernel;
419      }
420
421      /* Read the kernel data */
422      VBPERFSTART("VB_RKD");
423      if (0 != BootDeviceReadLBA(part_start + body_offset_sectors,
424                                 body_sectors,
425                                 params->kernel_buffer)) {
426        VBDEBUG(("Unable to read kernel data.\n"));
427        VBPERFEND("VB_RKD");
428        goto bad_kernel;
429      }
430      VBPERFEND("VB_RKD");
431
432      /* Verify kernel data */
433      if (0 != VerifyData((const uint8_t*)params->kernel_buffer,
434                          params->kernel_buffer_size,
435                          &preamble->body_signature, data_key)) {
436        VBDEBUG(("Kernel data verification failed.\n"));
437        goto bad_kernel;
438      }
439
440      /* Done with the kernel signing key, so can free it now */
441      RSAPublicKeyFree(data_key);
442      data_key = NULL;
443
444      /* If we're still here, the kernel is valid. */
445      /* Save the first good partition we find; that's the one we'll boot */
446      VBDEBUG(("Partition is good.\n"));
447      good_partition_key_block_valid = key_block_valid;
448      /* TODO: GPT partitions start at 1, but cgptlib starts them at 0.
449       * Adjust here, until cgptlib is fixed. */
450      good_partition = gpt.current_kernel + 1;
451      params->partition_number = gpt.current_kernel + 1;
452      GetCurrentKernelUniqueGuid(&gpt, &params->partition_guid);
453      /* TODO: GetCurrentKernelUniqueGuid() should take a destination size, or
454       * the dest should be a struct, so we know it's big enough. */
455      params->bootloader_address = preamble->bootloader_address;
456      params->bootloader_size = preamble->bootloader_size;
457
458      /* Update GPT to note this is the kernel we're trying */
459      GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_TRY);
460
461      /* If we're in recovery mode or we're about to boot a dev-signed kernel,
462       * there's no rollback protection, so we can stop at the first valid
463       * kernel. */
464      if (kBootRecovery == boot_mode || !key_block_valid) {
465        VBDEBUG(("In recovery mode or dev-signed kernel\n"));
466        break;
467      }
468
469      /* Otherwise, we do care about the key index in the TPM.  If the good
470       * partition's key version is the same as the tpm, then the TPM doesn't
471       * need updating; we can stop now.  Otherwise, we'll check all the other
472       * headers to see if they contain a newer key. */
473      if (combined_version == tpm_version) {
474        VBDEBUG(("Same kernel version\n"));
475        break;
476      }
477
478      /* Continue, so that we skip the error handling code below */
479      continue;
480
481   bad_kernel:
482      /* Handle errors parsing this kernel */
483      if (NULL != data_key)
484        RSAPublicKeyFree(data_key);
485
486      VBDEBUG(("Marking kernel as invalid.\n"));
487      GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD);
488
489
490    } /* while(GptNextKernelEntry) */
491  } while(0);
492
493  /* Free kernel buffer */
494  if (kbuf)
495    Free(kbuf);
496
497  /* Write and free GPT data */
498  WriteAndFreeGptData(&gpt);
499
500  /* Handle finding a good partition */
501  if (good_partition >= 0) {
502    VBDEBUG(("Good_partition >= 0\n"));
503
504    /* See if we need to update the TPM */
505    if (kBootRecovery != boot_mode && good_partition_key_block_valid) {
506      /* We only update the TPM in normal and developer boot modes.  In
507       * developer mode, we only advanced lowest_version for kernels with valid
508       * key blocks, and didn't count self-signed key blocks.  In recovery
509       * mode, the TPM stays PP-unlocked, so anything we write gets blown away
510       * by the firmware when we go back to normal mode. */
511      VBDEBUG(("Boot_flags = not recovery\n"));
512
513      if ((lowest_version > tpm_version) &&
514          (lowest_version != LOWEST_TPM_VERSION)) {
515        status = RollbackKernelWrite((uint32_t)lowest_version);
516        if (0 != status) {
517          VBDEBUG(("Error writing kernel versions to TPM.\n"));
518          if (status == TPM_E_MUST_REBOOT)
519            retval = LOAD_KERNEL_REBOOT;
520          else
521            recovery = VBNV_RECOVERY_RW_TPM_ERROR;
522          goto LoadKernelExit;
523        }
524      }
525    }
526
527    /* Lock the kernel versions */
528    status = RollbackKernelLock();
529    if (0 != status) {
530      VBDEBUG(("Error locking kernel versions.\n"));
531      /* Don't reboot to recovery mode if we're already there */
532      if (kBootRecovery != boot_mode) {
533        if (status == TPM_E_MUST_REBOOT)
534          retval = LOAD_KERNEL_REBOOT;
535        else
536          recovery = VBNV_RECOVERY_RW_TPM_ERROR;
537        goto LoadKernelExit;
538      }
539    }
540
541    /* Success! */
542    retval = LOAD_KERNEL_SUCCESS;
543  } else {
544    /* TODO: differentiate between finding an invalid kernel
545     * (found_partitions>0) and not finding one at all.  Right now we
546     * treat them the same, and return LOAD_KERNEL_INVALID for both. */
547    retval = LOAD_KERNEL_INVALID;
548  }
549
550LoadKernelExit:
551
552  /* Save whether the good partition's key block was fully verified */
553  VbNvSet(vnc, VBNV_FW_VERIFIED_KERNEL_KEY, good_partition_key_block_valid);
554
555  /* Store recovery request, if any, then tear down non-volatile storage */
556  VbNvSet(vnc, VBNV_RECOVERY_REQUEST, LOAD_KERNEL_RECOVERY == retval ?
557          recovery : VBNV_RECOVERY_NOT_REQUESTED);
558  VbNvTeardown(vnc);
559
560  if (shared) {
561    /* Save timer values */
562    shared->timer_load_kernel_enter = timer_enter;
563    shared->timer_load_kernel_exit = VbGetTimer();
564    /* Store how much shared data we used, if any */
565    params->shared_data_size = shared->data_used;
566  }
567
568  return retval;
569}
570