blob: 72cd2cc1fdf94d4875ef929f004bec58529c3951 [file] [log] [blame]
Randall Spangler7993f252013-01-29 15:01:12 -08001/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
Randall Spanglerd1836442010-06-10 09:59:04 -07002 * 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
Bill Richardson0c3ba242013-03-29 11:09:30 -07009#include "sysincludes.h"
Randall Spangler1b1998d2011-07-01 16:12:47 -070010
Randall Spanglerd1836442010-06-10 09:59:04 -070011#include "cgptlib.h"
Bill Richardson5deb67f2010-07-23 17:22:25 -070012#include "cgptlib_internal.h"
Simon Glass527ba812013-07-25 08:48:47 -060013#include "region.h"
14#include "gbb_access.h"
Randall Spangler95c40312011-03-09 15:54:16 -080015#include "gbb_header.h"
Randall Spanglerd1836442010-06-10 09:59:04 -070016#include "load_kernel_fw.h"
Randall Spanglerd1836442010-06-10 09:59:04 -070017#include "utility.h"
Randall Spanglere49e8af2011-07-08 13:03:32 -070018#include "vboot_api.h"
Randall Spangler83c88cf2010-06-11 16:14:18 -070019#include "vboot_common.h"
Randall Spanglere49e8af2011-07-08 13:03:32 -070020#include "vboot_kernel.h"
21
Randall Spanglerd1836442010-06-10 09:59:04 -070022#define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */
Stefan Reinauer55db6a62011-03-15 16:23:41 -070023#define LOWEST_TPM_VERSION 0xffffffff
Randall Spanglerd1836442010-06-10 09:59:04 -070024
Randall Spangler640fb512011-03-03 10:11:17 -080025typedef enum BootMode {
Randall Spangler7993f252013-01-29 15:01:12 -080026 kBootRecovery = 0, /* Recovery firmware, any dev switch position */
27 kBootNormal = 1, /* Normal boot - kernel must be verified */
28 kBootDev = 2 /* Developer boot - self-signed kernel ok */
Randall Spangler640fb512011-03-03 10:11:17 -080029} BootMode;
30
Randall Spangler7993f252013-01-29 15:01:12 -080031/**
32 * Allocate and read GPT data from the drive.
Randall Spangler83c88cf2010-06-11 16:14:18 -070033 *
Randall Spangler7993f252013-01-29 15:01:12 -080034 * The sector_bytes and drive_sectors fields should be filled on input. The
35 * primary and secondary header and entries are filled on output.
36 *
37 * Returns 0 if successful, 1 if error.
38 */
39int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData *gptdata)
40{
41 uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes;
Randall Spangler83c88cf2010-06-11 16:14:18 -070042
Randall Spangler7993f252013-01-29 15:01:12 -080043 /* No data to be written yet */
44 gptdata->modified = 0;
Randall Spangler83c88cf2010-06-11 16:14:18 -070045
Randall Spangler7993f252013-01-29 15:01:12 -080046 /* Allocate all buffers */
47 gptdata->primary_header = (uint8_t *)VbExMalloc(gptdata->sector_bytes);
48 gptdata->secondary_header =
49 (uint8_t *)VbExMalloc(gptdata->sector_bytes);
50 gptdata->primary_entries = (uint8_t *)VbExMalloc(TOTAL_ENTRIES_SIZE);
51 gptdata->secondary_entries = (uint8_t *)VbExMalloc(TOTAL_ENTRIES_SIZE);
Randall Spangler83c88cf2010-06-11 16:14:18 -070052
Randall Spangler7993f252013-01-29 15:01:12 -080053 if (gptdata->primary_header == NULL ||
54 gptdata->secondary_header == NULL ||
55 gptdata->primary_entries == NULL ||
56 gptdata->secondary_entries == NULL)
57 return 1;
Randall Spangler83c88cf2010-06-11 16:14:18 -070058
Randall Spangler7993f252013-01-29 15:01:12 -080059 /* Read data from the drive, skipping the protective MBR */
60 if (0 != VbExDiskRead(disk_handle, 1, 1, gptdata->primary_header))
61 return 1;
62 if (0 != VbExDiskRead(disk_handle, 2, entries_sectors,
63 gptdata->primary_entries))
64 return 1;
65 if (0 != VbExDiskRead(disk_handle,
66 gptdata->drive_sectors - entries_sectors - 1,
67 entries_sectors, gptdata->secondary_entries))
68 return 1;
69 if (0 != VbExDiskRead(disk_handle, gptdata->drive_sectors - 1, 1,
70 gptdata->secondary_header))
71 return 1;
Randall Spangler83c88cf2010-06-11 16:14:18 -070072
Randall Spangler7993f252013-01-29 15:01:12 -080073 return 0;
Randall Spangler83c88cf2010-06-11 16:14:18 -070074}
75
Randall Spangler7993f252013-01-29 15:01:12 -080076/**
77 * Write any changes for the GPT data back to the drive, then free the buffers.
Randall Spangler83c88cf2010-06-11 16:14:18 -070078 *
Randall Spangler7993f252013-01-29 15:01:12 -080079 * Returns 0 if successful, 1 if error.
80 */
81int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData *gptdata)
82{
83 int legacy = 0;
84 uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes;
Simon Glass47779882013-08-15 21:29:38 -060085 int ret = 1;
Randall Spangler83c88cf2010-06-11 16:14:18 -070086
Randall Spangler7993f252013-01-29 15:01:12 -080087 if (gptdata->primary_header) {
88 GptHeader *h = (GptHeader *)(gptdata->primary_header);
Simon Glass47779882013-08-15 21:29:38 -060089
90 /*
91 * Avoid even looking at this data if we don't need to. We
92 * may in fact not have read it from disk if the read failed,
93 * and this avoids a valgrind complaint.
94 */
95 if (gptdata->modified) {
96 legacy = !Memcmp(h->signature, GPT_HEADER_SIGNATURE2,
97 GPT_HEADER_SIGNATURE_SIZE);
98 }
Randall Spangler7993f252013-01-29 15:01:12 -080099 if (gptdata->modified & GPT_MODIFIED_HEADER1) {
100 if (legacy) {
101 VBDEBUG(("Not updating GPT header 1: "
102 "legacy mode is enabled.\n"));
103 } else {
104 VBDEBUG(("Updating GPT header 1\n"));
105 if (0 != VbExDiskWrite(disk_handle, 1, 1,
106 gptdata->primary_header))
Simon Glass47779882013-08-15 21:29:38 -0600107 goto fail;
Randall Spangler7993f252013-01-29 15:01:12 -0800108 }
109 }
Randall Spangler7993f252013-01-29 15:01:12 -0800110 }
Randall Spangler83c88cf2010-06-11 16:14:18 -0700111
Randall Spangler7993f252013-01-29 15:01:12 -0800112 if (gptdata->primary_entries) {
113 if (gptdata->modified & GPT_MODIFIED_ENTRIES1) {
114 if (legacy) {
115 VBDEBUG(("Not updating GPT entries 1: "
116 "legacy mode is enabled.\n"));
117 } else {
118 VBDEBUG(("Updating GPT entries 1\n"));
119 if (0 != VbExDiskWrite(disk_handle, 2,
120 entries_sectors,
121 gptdata->primary_entries))
Simon Glass47779882013-08-15 21:29:38 -0600122 goto fail;
Randall Spangler7993f252013-01-29 15:01:12 -0800123 }
124 }
Randall Spangler7993f252013-01-29 15:01:12 -0800125 }
Randall Spangler83c88cf2010-06-11 16:14:18 -0700126
Randall Spangler7993f252013-01-29 15:01:12 -0800127 if (gptdata->secondary_entries) {
128 if (gptdata->modified & GPT_MODIFIED_ENTRIES2) {
129 VBDEBUG(("Updating GPT header 2\n"));
130 if (0 != VbExDiskWrite(disk_handle,
131 gptdata->drive_sectors - entries_sectors - 1,
132 entries_sectors, gptdata->secondary_entries))
Simon Glass47779882013-08-15 21:29:38 -0600133 goto fail;
Randall Spangler7993f252013-01-29 15:01:12 -0800134 }
Randall Spangler7993f252013-01-29 15:01:12 -0800135 }
Randall Spangler83c88cf2010-06-11 16:14:18 -0700136
Randall Spangler7993f252013-01-29 15:01:12 -0800137 if (gptdata->secondary_header) {
138 if (gptdata->modified & GPT_MODIFIED_HEADER2) {
139 VBDEBUG(("Updating GPT entries 2\n"));
140 if (0 != VbExDiskWrite(disk_handle,
141 gptdata->drive_sectors - 1, 1,
142 gptdata->secondary_header))
Simon Glass47779882013-08-15 21:29:38 -0600143 goto fail;
Randall Spangler7993f252013-01-29 15:01:12 -0800144 }
Randall Spangler7993f252013-01-29 15:01:12 -0800145 }
Randall Spangler83c88cf2010-06-11 16:14:18 -0700146
Simon Glass47779882013-08-15 21:29:38 -0600147 ret = 0;
148
149fail:
150 /* Avoid leaking memory on disk write failure */
151 if (gptdata->primary_header)
152 VbExFree(gptdata->primary_header);
153 if (gptdata->primary_entries)
154 VbExFree(gptdata->primary_entries);
155 if (gptdata->secondary_entries)
156 VbExFree(gptdata->secondary_entries);
157 if (gptdata->secondary_header)
158 VbExFree(gptdata->secondary_header);
159
Randall Spangler7993f252013-01-29 15:01:12 -0800160 /* Success */
Simon Glass47779882013-08-15 21:29:38 -0600161 return ret;
Randall Spangler83c88cf2010-06-11 16:14:18 -0700162}
163
Simon Glass527ba812013-07-25 08:48:47 -0600164VbError_t LoadKernel(LoadKernelParams *params, VbCommonParams *cparams)
Randall Spangler7993f252013-01-29 15:01:12 -0800165{
166 VbSharedDataHeader *shared =
167 (VbSharedDataHeader *)params->shared_data_blob;
168 VbSharedDataKernelCall *shcall = NULL;
169 VbNvContext* vnc = params->nv_context;
Simon Glass527ba812013-07-25 08:48:47 -0600170 VbPublicKey* kernel_subkey = NULL;
171 int free_kernel_subkey = 0;
Randall Spangler7993f252013-01-29 15:01:12 -0800172 GptData gpt;
173 uint64_t part_start, part_size;
174 uint64_t blba;
175 uint64_t kbuf_sectors;
176 uint8_t* kbuf = NULL;
177 int found_partitions = 0;
178 int good_partition = -1;
179 int good_partition_key_block_valid = 0;
180 uint32_t lowest_version = LOWEST_TPM_VERSION;
181 int rec_switch, dev_switch;
182 BootMode boot_mode;
183 uint32_t require_official_os = 0;
Bill Richardsonfa9d7782011-11-09 09:11:34 -0800184
Randall Spangler7993f252013-01-29 15:01:12 -0800185 VbError_t retval = VBERROR_UNKNOWN;
186 int recovery = VBNV_RECOVERY_LK_UNSPECIFIED;
Randall Spanglerd1836442010-06-10 09:59:04 -0700187
Randall Spangler7993f252013-01-29 15:01:12 -0800188 /* Sanity Checks */
189 if (!params->bytes_per_lba ||
190 !params->ending_lba) {
191 VBDEBUG(("LoadKernel() called with invalid params\n"));
192 retval = VBERROR_INVALID_PARAMETER;
193 goto LoadKernelExit;
194 }
Randall Spangler640fb512011-03-03 10:11:17 -0800195
Randall Spangler7993f252013-01-29 15:01:12 -0800196 /* Clear output params in case we fail */
197 params->partition_number = 0;
198 params->bootloader_address = 0;
199 params->bootloader_size = 0;
Bill Richardsone2729402010-07-22 12:23:47 -0700200
Randall Spangler7993f252013-01-29 15:01:12 -0800201 /* Calculate switch positions and boot mode */
202 rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0);
203 dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0);
204 if (rec_switch) {
205 boot_mode = kBootRecovery;
206 } else if (dev_switch) {
207 boot_mode = kBootDev;
208 VbNvGet(vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &require_official_os);
209 } else {
210 boot_mode = kBootNormal;
211 }
Randall Spanglerad6824b2011-03-16 19:07:33 -0700212
Randall Spangler7993f252013-01-29 15:01:12 -0800213 /*
214 * Set up tracking for this call. This wraps around if called many
215 * times, so we need to initialize the call entry each time.
216 */
217 shcall = shared->lk_calls + (shared->lk_call_count
218 & (VBSD_MAX_KERNEL_CALLS - 1));
219 Memset(shcall, 0, sizeof(VbSharedDataKernelCall));
220 shcall->boot_flags = (uint32_t)params->boot_flags;
221 shcall->boot_mode = boot_mode;
222 shcall->sector_size = (uint32_t)params->bytes_per_lba;
223 shcall->sector_count = params->ending_lba + 1;
224 shared->lk_call_count++;
Randall Spangler17c71262011-03-18 11:24:27 -0700225
Randall Spangler7993f252013-01-29 15:01:12 -0800226 /* Initialization */
227 blba = params->bytes_per_lba;
228 kbuf_sectors = KBUF_SIZE / blba;
229 if (0 == kbuf_sectors) {
230 VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n"));
231 retval = VBERROR_INVALID_PARAMETER;
232 goto LoadKernelExit;
233 }
Randall Spangler17c71262011-03-18 11:24:27 -0700234
Randall Spangler7993f252013-01-29 15:01:12 -0800235 if (kBootRecovery == boot_mode) {
236 /* Use the recovery key to verify the kernel */
Simon Glass527ba812013-07-25 08:48:47 -0600237 retval = VbGbbReadRecoveryKey(cparams, &kernel_subkey);
238 if (VBERROR_SUCCESS != retval)
239 goto LoadKernelExit;
240 free_kernel_subkey = 1;
Randall Spangler7993f252013-01-29 15:01:12 -0800241 } else {
242 /* Use the kernel subkey passed from LoadFirmware(). */
243 kernel_subkey = &shared->kernel_subkey;
244 }
Randall Spangler4bb5e4b2010-08-19 09:05:22 -0700245
Randall Spangler7993f252013-01-29 15:01:12 -0800246 /* Read GPT data */
247 gpt.sector_bytes = (uint32_t)blba;
248 gpt.drive_sectors = params->ending_lba + 1;
249 if (0 != AllocAndReadGptData(params->disk_handle, &gpt)) {
250 VBDEBUG(("Unable to read GPT data\n"));
251 shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR;
252 goto bad_gpt;
253 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700254
Randall Spangler7993f252013-01-29 15:01:12 -0800255 /* Initialize GPT library */
256 if (GPT_SUCCESS != GptInit(&gpt)) {
257 VBDEBUG(("Error parsing GPT\n"));
258 shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR;
259 goto bad_gpt;
260 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700261
Randall Spangler7993f252013-01-29 15:01:12 -0800262 /* Allocate kernel header buffers */
263 kbuf = (uint8_t*)VbExMalloc(KBUF_SIZE);
264 if (!kbuf)
265 goto bad_gpt;
Randall Spanglerd1836442010-06-10 09:59:04 -0700266
Randall Spangler7993f252013-01-29 15:01:12 -0800267 /* Loop over candidate kernel partitions */
268 while (GPT_SUCCESS ==
269 GptNextKernelEntry(&gpt, &part_start, &part_size)) {
270 VbSharedDataKernelPart *shpart = NULL;
271 VbKeyBlockHeader *key_block;
272 VbKernelPreambleHeader *preamble;
273 RSAPublicKey *data_key = NULL;
274 uint64_t key_version;
275 uint32_t combined_version;
276 uint64_t body_offset;
277 uint64_t body_offset_sectors;
278 uint64_t body_sectors;
279 int key_block_valid = 1;
Randall Spanglerd1836442010-06-10 09:59:04 -0700280
Randall Spangler7993f252013-01-29 15:01:12 -0800281 VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n",
282 part_start, part_size));
Randall Spanglerd1836442010-06-10 09:59:04 -0700283
Randall Spangler7993f252013-01-29 15:01:12 -0800284 /*
285 * Set up tracking for this partition. This wraps around if
286 * called many times, so initialize the partition entry each
287 * time.
288 */
289 shpart = shcall->parts + (shcall->kernel_parts_found
290 & (VBSD_MAX_KERNEL_PARTS - 1));
291 Memset(shpart, 0, sizeof(VbSharedDataKernelPart));
292 shpart->sector_start = part_start;
293 shpart->sector_count = part_size;
294 /*
295 * TODO: GPT partitions start at 1, but cgptlib starts them at
296 * 0. Adjust here, until cgptlib is fixed.
297 */
298 shpart->gpt_index = (uint8_t)(gpt.current_kernel + 1);
299 shcall->kernel_parts_found++;
Randall Spangler695cd162010-06-15 23:38:23 -0700300
Randall Spangler7993f252013-01-29 15:01:12 -0800301 /* Found at least one kernel partition. */
302 found_partitions++;
Randall Spangler17c71262011-03-18 11:24:27 -0700303
Randall Spangler7993f252013-01-29 15:01:12 -0800304 /* Read the first part of the kernel partition. */
305 if (part_size < kbuf_sectors) {
306 VBDEBUG(("Partition too small to hold kernel.\n"));
307 shpart->check_result = VBSD_LKP_CHECK_TOO_SMALL;
308 goto bad_kernel;
309 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700310
Randall Spangler7993f252013-01-29 15:01:12 -0800311 if (0 != VbExDiskRead(params->disk_handle, part_start,
312 kbuf_sectors, kbuf)) {
313 VBDEBUG(("Unable to read start of partition.\n"));
314 shpart->check_result = VBSD_LKP_CHECK_READ_START;
315 goto bad_kernel;
316 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700317
Randall Spangler7993f252013-01-29 15:01:12 -0800318 /* Verify the key block. */
319 key_block = (VbKeyBlockHeader*)kbuf;
320 if (0 != KeyBlockVerify(key_block, KBUF_SIZE,
321 kernel_subkey, 0)) {
322 VBDEBUG(("Verifying key block signature failed.\n"));
323 shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_SIG;
324 key_block_valid = 0;
Randall Spangler17c71262011-03-18 11:24:27 -0700325
Randall Spangler7993f252013-01-29 15:01:12 -0800326 /* If not in developer mode, this kernel is bad. */
327 if (kBootDev != boot_mode)
328 goto bad_kernel;
Randall Spanglerd1836442010-06-10 09:59:04 -0700329
Randall Spangler7993f252013-01-29 15:01:12 -0800330 /*
331 * In developer mode, we can explictly disallow
332 * self-signed kernels
333 */
334 if (require_official_os) {
335 VBDEBUG(("Self-signed kernels not enabled.\n"));
336 shpart->check_result =
337 VBSD_LKP_CHECK_SELF_SIGNED;
338 goto bad_kernel;
339 }
Randall Spangler640fb512011-03-03 10:11:17 -0800340
Randall Spangler7993f252013-01-29 15:01:12 -0800341 /*
342 * Allow the kernel if the SHA-512 hash of the key
343 * block is valid.
344 */
345 if (0 != KeyBlockVerify(key_block, KBUF_SIZE,
346 kernel_subkey, 1)) {
347 VBDEBUG(("Verifying key block hash failed.\n"));
348 shpart->check_result =
349 VBSD_LKP_CHECK_KEY_BLOCK_HASH;
350 goto bad_kernel;
351 }
352 }
Bill Richardsonfa9d7782011-11-09 09:11:34 -0800353
Randall Spangler7993f252013-01-29 15:01:12 -0800354 /* Check the key block flags against the current boot mode. */
355 if (!(key_block->key_block_flags &
356 (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 :
357 KEY_BLOCK_FLAG_DEVELOPER_0))) {
358 VBDEBUG(("Key block developer flag mismatch.\n"));
359 shpart->check_result = VBSD_LKP_CHECK_DEV_MISMATCH;
360 key_block_valid = 0;
361 }
362 if (!(key_block->key_block_flags &
363 (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 :
364 KEY_BLOCK_FLAG_RECOVERY_0))) {
365 VBDEBUG(("Key block recovery flag mismatch.\n"));
366 shpart->check_result = VBSD_LKP_CHECK_REC_MISMATCH;
367 key_block_valid = 0;
368 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700369
Randall Spangler7993f252013-01-29 15:01:12 -0800370 /* Check for rollback of key version except in recovery mode. */
371 key_version = key_block->data_key.key_version;
372 if (kBootRecovery != boot_mode) {
373 if (key_version < (shared->kernel_version_tpm >> 16)) {
374 VBDEBUG(("Key version too old.\n"));
375 shpart->check_result =
376 VBSD_LKP_CHECK_KEY_ROLLBACK;
377 key_block_valid = 0;
378 }
379 if (key_version > 0xFFFF) {
380 /*
381 * Key version is stored in 16 bits in the TPM,
382 * so key versions greater than 0xFFFF can't be
383 * stored properly.
384 */
385 VBDEBUG(("Key version > 0xFFFF.\n"));
386 shpart->check_result =
387 VBSD_LKP_CHECK_KEY_ROLLBACK;
388 key_block_valid = 0;
389 }
390 }
Randall Spangler640fb512011-03-03 10:11:17 -0800391
Randall Spangler7993f252013-01-29 15:01:12 -0800392 /* If not in developer mode, key block required to be valid. */
393 if (kBootDev != boot_mode && !key_block_valid) {
394 VBDEBUG(("Key block is invalid.\n"));
395 goto bad_kernel;
396 }
Randall Spangler640fb512011-03-03 10:11:17 -0800397
Randall Spangler7993f252013-01-29 15:01:12 -0800398 /* Get key for preamble/data verification from the key block. */
399 data_key = PublicKeyToRSA(&key_block->data_key);
400 if (!data_key) {
401 VBDEBUG(("Data key bad.\n"));
402 shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE;
403 goto bad_kernel;
404 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700405
Randall Spangler7993f252013-01-29 15:01:12 -0800406 /* Verify the preamble, which follows the key block */
407 preamble = (VbKernelPreambleHeader *)
408 (kbuf + key_block->key_block_size);
409 if ((0 != VerifyKernelPreamble(
410 preamble,
411 KBUF_SIZE - key_block->key_block_size,
412 data_key))) {
413 VBDEBUG(("Preamble verification failed.\n"));
414 shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE;
415 goto bad_kernel;
416 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700417
Randall Spangler7993f252013-01-29 15:01:12 -0800418 /*
419 * If the key block is valid and we're not in recovery mode,
420 * check for rollback of the kernel version.
421 */
422 combined_version = (uint32_t)(
423 (key_version << 16) |
424 (preamble->kernel_version & 0xFFFF));
425 shpart->combined_version = combined_version;
426 if (key_block_valid && kBootRecovery != boot_mode) {
427 if (combined_version < shared->kernel_version_tpm) {
428 VBDEBUG(("Kernel version too low.\n"));
429 shpart->check_result =
430 VBSD_LKP_CHECK_KERNEL_ROLLBACK;
431 /*
432 * If not in developer mode, kernel version
433 * must be valid.
434 */
435 if (kBootDev != boot_mode)
436 goto bad_kernel;
437 }
438 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700439
Randall Spangler7993f252013-01-29 15:01:12 -0800440 VBDEBUG(("Kernel preamble is good.\n"));
441 shpart->check_result = VBSD_LKP_CHECK_PREAMBLE_VALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700442
Randall Spangler7993f252013-01-29 15:01:12 -0800443 /* Check for lowest version from a valid header. */
444 if (key_block_valid && lowest_version > combined_version)
445 lowest_version = combined_version;
446 else {
447 VBDEBUG(("Key block valid: %d\n", key_block_valid));
448 VBDEBUG(("Combined version: %u\n",
449 (unsigned) combined_version));
450 }
Randall Spangler695cd162010-06-15 23:38:23 -0700451
Randall Spangler7993f252013-01-29 15:01:12 -0800452 /*
453 * If we already have a good kernel, no need to read another
454 * one; we only needed to look at the versions to check for
455 * rollback. So skip to the next kernel preamble.
456 */
457 if (-1 != good_partition)
458 continue;
Randall Spanglerd1836442010-06-10 09:59:04 -0700459
Randall Spangler7993f252013-01-29 15:01:12 -0800460 /* Verify kernel body starts at multiple of sector size. */
461 body_offset = key_block->key_block_size +
462 preamble->preamble_size;
463 if (0 != body_offset % blba) {
464 VBDEBUG(("Kernel body not at multiple of "
465 "sector size.\n"));
466 shpart->check_result = VBSD_LKP_CHECK_BODY_OFFSET;
467 goto bad_kernel;
468 }
469 body_offset_sectors = body_offset / blba;
Randall Spanglerd1836442010-06-10 09:59:04 -0700470
Randall Spangler7993f252013-01-29 15:01:12 -0800471 body_sectors =
472 (preamble->body_signature.data_size + blba - 1) / blba;
473 if (!params->kernel_buffer) {
474 /* Get kernel load address and size from the header. */
475 params->kernel_buffer =
476 (void *)((long)preamble->body_load_address);
477 params->kernel_buffer_size = body_sectors * blba;
478 } else {
479 /* Verify kernel body fits in the buffer */
480 if (body_sectors * blba > params->kernel_buffer_size) {
481 VBDEBUG(("Kernel body doesn't "
482 "fit in memory.\n"));
483 shpart->check_result =
484 VBSD_LKP_CHECK_BODY_EXCEEDS_MEM;
485 goto bad_kernel;
486 }
487 }
Randall Spangler4bb5e4b2010-08-19 09:05:22 -0700488
Randall Spangler7993f252013-01-29 15:01:12 -0800489 /* Verify kernel body fits in the partition */
490 if (body_offset_sectors + body_sectors > part_size) {
491 VBDEBUG(("Kernel body doesn't fit in partition.\n"));
492 shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_PART;
493 goto bad_kernel;
494 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700495
Randall Spangler7993f252013-01-29 15:01:12 -0800496 /* Read the kernel data */
Randall Spangler7993f252013-01-29 15:01:12 -0800497 if (0 != VbExDiskRead(params->disk_handle,
498 part_start + body_offset_sectors,
499 body_sectors, params->kernel_buffer)) {
500 VBDEBUG(("Unable to read kernel data.\n"));
Randall Spangler7993f252013-01-29 15:01:12 -0800501 shpart->check_result = VBSD_LKP_CHECK_READ_DATA;
502 goto bad_kernel;
503 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700504
Randall Spangler7993f252013-01-29 15:01:12 -0800505 /* Verify kernel data */
506 if (0 != VerifyData((const uint8_t *)params->kernel_buffer,
507 params->kernel_buffer_size,
508 &preamble->body_signature, data_key)) {
509 VBDEBUG(("Kernel data verification failed.\n"));
510 shpart->check_result = VBSD_LKP_CHECK_VERIFY_DATA;
511 goto bad_kernel;
512 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700513
Randall Spangler7993f252013-01-29 15:01:12 -0800514 /* Done with the kernel signing key, so can free it now */
515 RSAPublicKeyFree(data_key);
516 data_key = NULL;
Randall Spanglerd1836442010-06-10 09:59:04 -0700517
Randall Spangler7993f252013-01-29 15:01:12 -0800518 /*
519 * If we're still here, the kernel is valid. Save the first
520 * good partition we find; that's the one we'll boot.
521 */
522 VBDEBUG(("Partition is good.\n"));
523 shpart->check_result = VBSD_LKP_CHECK_KERNEL_GOOD;
524 if (key_block_valid)
525 shpart->flags |= VBSD_LKP_FLAG_KEY_BLOCK_VALID;
Randall Spangler17c71262011-03-18 11:24:27 -0700526
Randall Spangler7993f252013-01-29 15:01:12 -0800527 good_partition_key_block_valid = key_block_valid;
528 /*
529 * TODO: GPT partitions start at 1, but cgptlib starts them at
530 * 0. Adjust here, until cgptlib is fixed.
531 */
532 good_partition = gpt.current_kernel + 1;
533 params->partition_number = gpt.current_kernel + 1;
534 GetCurrentKernelUniqueGuid(&gpt, &params->partition_guid);
535 /*
536 * TODO: GetCurrentKernelUniqueGuid() should take a destination
537 * size, or the dest should be a struct, so we know it's big
538 * enough.
539 */
Randall Spangler7993f252013-01-29 15:01:12 -0800540 params->bootloader_address = preamble->bootloader_address;
541 params->bootloader_size = preamble->bootloader_size;
Randall Spangler741d2b22010-08-20 16:37:12 -0700542
Randall Spangler7993f252013-01-29 15:01:12 -0800543 /* Update GPT to note this is the kernel we're trying */
544 GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_TRY);
Randall Spangler741d2b22010-08-20 16:37:12 -0700545
Randall Spangler7993f252013-01-29 15:01:12 -0800546 /*
547 * If we're in recovery mode or we're about to boot a
548 * dev-signed kernel, there's no rollback protection, so we can
549 * stop at the first valid kernel.
550 */
551 if (kBootRecovery == boot_mode || !key_block_valid) {
552 VBDEBUG(("In recovery mode or dev-signed kernel\n"));
553 break;
554 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700555
Randall Spangler7993f252013-01-29 15:01:12 -0800556 /*
557 * Otherwise, we do care about the key index in the TPM. If
558 * the good partition's key version is the same as the tpm,
559 * then the TPM doesn't need updating; we can stop now.
560 * Otherwise, we'll check all the other headers to see if they
561 * contain a newer key.
562 */
563 if (combined_version == shared->kernel_version_tpm) {
564 VBDEBUG(("Same kernel version\n"));
565 break;
566 }
Randall Spangler741d2b22010-08-20 16:37:12 -0700567
Randall Spangler7993f252013-01-29 15:01:12 -0800568 /* Continue, so that we skip the error handling code below */
569 continue;
Randall Spangler741d2b22010-08-20 16:37:12 -0700570
Randall Spangler7993f252013-01-29 15:01:12 -0800571 bad_kernel:
572 /* Handle errors parsing this kernel */
573 if (NULL != data_key)
574 RSAPublicKeyFree(data_key);
Randall Spangler741d2b22010-08-20 16:37:12 -0700575
Randall Spangler7993f252013-01-29 15:01:12 -0800576 VBDEBUG(("Marking kernel as invalid.\n"));
577 GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD);
Randall Spangler741d2b22010-08-20 16:37:12 -0700578
579
Randall Spangler7993f252013-01-29 15:01:12 -0800580 } /* while(GptNextKernelEntry) */
Randall Spangler49cb0d32013-01-29 14:28:16 -0800581
Randall Spangler7993f252013-01-29 15:01:12 -0800582 bad_gpt:
Randall Spanglerd1836442010-06-10 09:59:04 -0700583
Randall Spangler7993f252013-01-29 15:01:12 -0800584 /* Free kernel buffer */
585 if (kbuf)
586 VbExFree(kbuf);
Randall Spanglerd1836442010-06-10 09:59:04 -0700587
Randall Spangler7993f252013-01-29 15:01:12 -0800588 /* Write and free GPT data */
589 WriteAndFreeGptData(params->disk_handle, &gpt);
Randall Spanglerd1836442010-06-10 09:59:04 -0700590
Randall Spangler7993f252013-01-29 15:01:12 -0800591 /* Handle finding a good partition */
592 if (good_partition >= 0) {
593 VBDEBUG(("Good_partition >= 0\n"));
594 shcall->check_result = VBSD_LKC_CHECK_GOOD_PARTITION;
595 shared->kernel_version_lowest = lowest_version;
596 /*
597 * Sanity check - only store a new TPM version if we found one.
598 * If lowest_version is still at its initial value, we didn't
599 * find one; for example, we're in developer mode and just
600 * didn't look.
601 */
602 if (lowest_version != LOWEST_TPM_VERSION &&
603 lowest_version > shared->kernel_version_tpm)
604 shared->kernel_version_tpm = lowest_version;
Randall Spanglerd1836442010-06-10 09:59:04 -0700605
Randall Spangler7993f252013-01-29 15:01:12 -0800606 /* Success! */
607 retval = VBERROR_SUCCESS;
608 } else if (found_partitions > 0) {
609 shcall->check_result = VBSD_LKC_CHECK_INVALID_PARTITIONS;
610 recovery = VBNV_RECOVERY_RW_INVALID_OS;
611 retval = VBERROR_INVALID_KERNEL_FOUND;
612 } else {
613 shcall->check_result = VBSD_LKC_CHECK_NO_PARTITIONS;
614 recovery = VBNV_RECOVERY_RW_NO_OS;
615 retval = VBERROR_NO_KERNEL_FOUND;
616 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700617
Randall Spangler7993f252013-01-29 15:01:12 -0800618 LoadKernelExit:
Randall Spangler640fb512011-03-03 10:11:17 -0800619
Randall Spangler7993f252013-01-29 15:01:12 -0800620 /* Store recovery request, if any */
621 VbNvSet(vnc, VBNV_RECOVERY_REQUEST, VBERROR_SUCCESS != retval ?
622 recovery : VBNV_RECOVERY_NOT_REQUESTED);
Randall Spangler640fb512011-03-03 10:11:17 -0800623
Randall Spangler7993f252013-01-29 15:01:12 -0800624 /*
625 * If LoadKernel() was called with bad parameters, shcall may not be
626 * initialized.
627 */
628 if (shcall)
629 shcall->return_code = (uint8_t)retval;
Randall Spangler17c71262011-03-18 11:24:27 -0700630
Randall Spangler7993f252013-01-29 15:01:12 -0800631 /* Save whether the good partition's key block was fully verified */
632 if (good_partition_key_block_valid)
633 shared->flags |= VBSD_KERNEL_KEY_VERIFIED;
Randall Spangler17c71262011-03-18 11:24:27 -0700634
Randall Spangler7993f252013-01-29 15:01:12 -0800635 /* Store how much shared data we used, if any */
636 params->shared_data_size = shared->data_used;
Randall Spangler95c40312011-03-09 15:54:16 -0800637
Simon Glass527ba812013-07-25 08:48:47 -0600638 if (free_kernel_subkey)
639 VbExFree(kernel_subkey);
640
Randall Spangler7993f252013-01-29 15:01:12 -0800641 return retval;
Randall Spanglerd1836442010-06-10 09:59:04 -0700642}