blob: 1e7b7d0d143df167f9ae949fb602e1c3d40d0461 [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 Spangler7c3ae422016-05-11 13:50:18 -070011#include "2common.h"
12#include "2sha.h"
Randall Spanglerd1836442010-06-10 09:59:04 -070013#include "cgptlib.h"
Bill Richardson5deb67f2010-07-23 17:22:25 -070014#include "cgptlib_internal.h"
Simon Glass527ba812013-07-25 08:48:47 -060015#include "region.h"
16#include "gbb_access.h"
Randall Spangler95c40312011-03-09 15:54:16 -080017#include "gbb_header.h"
Dan Ehrenberg7c2beb02014-10-21 16:15:54 -070018#include "gpt_misc.h"
Randall Spanglerd1836442010-06-10 09:59:04 -070019#include "load_kernel_fw.h"
Randall Spangler946abf12016-04-15 14:49:40 -070020#include "rollback_index.h"
Randall Spanglerd1836442010-06-10 09:59:04 -070021#include "utility.h"
Randall Spanglere49e8af2011-07-08 13:03:32 -070022#include "vboot_api.h"
Randall Spangler83c88cf2010-06-11 16:14:18 -070023#include "vboot_common.h"
Randall Spanglere49e8af2011-07-08 13:03:32 -070024#include "vboot_kernel.h"
25
Randall Spanglerd1836442010-06-10 09:59:04 -070026#define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */
Stefan Reinauer55db6a62011-03-15 16:23:41 -070027#define LOWEST_TPM_VERSION 0xffffffff
Randall Spanglerd1836442010-06-10 09:59:04 -070028
Randall Spangler640fb512011-03-03 10:11:17 -080029typedef enum BootMode {
Randall Spangler7993f252013-01-29 15:01:12 -080030 kBootRecovery = 0, /* Recovery firmware, any dev switch position */
31 kBootNormal = 1, /* Normal boot - kernel must be verified */
32 kBootDev = 2 /* Developer boot - self-signed kernel ok */
Randall Spangler640fb512011-03-03 10:11:17 -080033} BootMode;
34
Simon Glass527ba812013-07-25 08:48:47 -060035VbError_t LoadKernel(LoadKernelParams *params, VbCommonParams *cparams)
Randall Spangler7993f252013-01-29 15:01:12 -080036{
37 VbSharedDataHeader *shared =
38 (VbSharedDataHeader *)params->shared_data_blob;
39 VbSharedDataKernelCall *shcall = NULL;
40 VbNvContext* vnc = params->nv_context;
Simon Glass527ba812013-07-25 08:48:47 -060041 VbPublicKey* kernel_subkey = NULL;
42 int free_kernel_subkey = 0;
Randall Spangler7993f252013-01-29 15:01:12 -080043 GptData gpt;
44 uint64_t part_start, part_size;
45 uint64_t blba;
46 uint64_t kbuf_sectors;
47 uint8_t* kbuf = NULL;
48 int found_partitions = 0;
49 int good_partition = -1;
50 int good_partition_key_block_valid = 0;
51 uint32_t lowest_version = LOWEST_TPM_VERSION;
52 int rec_switch, dev_switch;
53 BootMode boot_mode;
54 uint32_t require_official_os = 0;
Randall Spangler4184e622014-10-08 16:41:01 -070055 uint32_t body_toread;
56 uint8_t *body_readptr;
Bill Richardsonfa9d7782011-11-09 09:11:34 -080057
Randall Spangler7993f252013-01-29 15:01:12 -080058 VbError_t retval = VBERROR_UNKNOWN;
59 int recovery = VBNV_RECOVERY_LK_UNSPECIFIED;
Randall Spanglerd1836442010-06-10 09:59:04 -070060
Randall Spangler7993f252013-01-29 15:01:12 -080061 /* Sanity Checks */
62 if (!params->bytes_per_lba ||
Dan Ehrenberg3f4d8d02014-12-02 08:21:57 -080063 !params->streaming_lba_count) {
Randall Spangler7993f252013-01-29 15:01:12 -080064 VBDEBUG(("LoadKernel() called with invalid params\n"));
65 retval = VBERROR_INVALID_PARAMETER;
66 goto LoadKernelExit;
67 }
Randall Spangler640fb512011-03-03 10:11:17 -080068
Randall Spangler7993f252013-01-29 15:01:12 -080069 /* Clear output params in case we fail */
70 params->partition_number = 0;
71 params->bootloader_address = 0;
72 params->bootloader_size = 0;
Furquan Shaikhb7d1f032015-02-03 16:28:31 -080073 params->flags = 0;
Bill Richardsone2729402010-07-22 12:23:47 -070074
Randall Spangler7993f252013-01-29 15:01:12 -080075 /* Calculate switch positions and boot mode */
76 rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0);
77 dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0);
78 if (rec_switch) {
79 boot_mode = kBootRecovery;
80 } else if (dev_switch) {
81 boot_mode = kBootDev;
82 VbNvGet(vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &require_official_os);
Randall Spangler946abf12016-04-15 14:49:40 -070083
84 if (params->fwmp &&
85 (params->fwmp->flags & FWMP_DEV_ENABLE_OFFICIAL_ONLY))
86 require_official_os = 1;
Randall Spangler7993f252013-01-29 15:01:12 -080087 } else {
88 boot_mode = kBootNormal;
89 }
Randall Spanglerad6824b2011-03-16 19:07:33 -070090
Randall Spangler7993f252013-01-29 15:01:12 -080091 /*
92 * Set up tracking for this call. This wraps around if called many
93 * times, so we need to initialize the call entry each time.
94 */
95 shcall = shared->lk_calls + (shared->lk_call_count
Gwendal Grignoue2e14ae2015-04-27 09:46:52 -070096 & (VBSD_MAX_KERNEL_CALLS - 1));
Randall Spangler664096b2016-10-13 16:16:41 -070097 memset(shcall, 0, sizeof(VbSharedDataKernelCall));
Randall Spangler7993f252013-01-29 15:01:12 -080098 shcall->boot_flags = (uint32_t)params->boot_flags;
99 shcall->boot_mode = boot_mode;
100 shcall->sector_size = (uint32_t)params->bytes_per_lba;
Dan Ehrenberg3f4d8d02014-12-02 08:21:57 -0800101 shcall->sector_count = params->streaming_lba_count;
Randall Spangler7993f252013-01-29 15:01:12 -0800102 shared->lk_call_count++;
Randall Spangler17c71262011-03-18 11:24:27 -0700103
Randall Spangler7993f252013-01-29 15:01:12 -0800104 /* Initialization */
105 blba = params->bytes_per_lba;
106 kbuf_sectors = KBUF_SIZE / blba;
107 if (0 == kbuf_sectors) {
108 VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n"));
109 retval = VBERROR_INVALID_PARAMETER;
110 goto LoadKernelExit;
111 }
Randall Spangler17c71262011-03-18 11:24:27 -0700112
Randall Spangler7993f252013-01-29 15:01:12 -0800113 if (kBootRecovery == boot_mode) {
114 /* Use the recovery key to verify the kernel */
Simon Glass527ba812013-07-25 08:48:47 -0600115 retval = VbGbbReadRecoveryKey(cparams, &kernel_subkey);
116 if (VBERROR_SUCCESS != retval)
117 goto LoadKernelExit;
118 free_kernel_subkey = 1;
Randall Spangler7993f252013-01-29 15:01:12 -0800119 } else {
120 /* Use the kernel subkey passed from LoadFirmware(). */
121 kernel_subkey = &shared->kernel_subkey;
122 }
Randall Spangler4bb5e4b2010-08-19 09:05:22 -0700123
Randall Spangler7993f252013-01-29 15:01:12 -0800124 /* Read GPT data */
125 gpt.sector_bytes = (uint32_t)blba;
Dan Ehrenberg3f4d8d02014-12-02 08:21:57 -0800126 gpt.streaming_drive_sectors = params->streaming_lba_count;
127 gpt.gpt_drive_sectors = params->gpt_lba_count;
128 gpt.flags = params->boot_flags & BOOT_FLAG_EXTERNAL_GPT
129 ? GPT_FLAG_EXTERNAL : 0;
Randall Spangler7993f252013-01-29 15:01:12 -0800130 if (0 != AllocAndReadGptData(params->disk_handle, &gpt)) {
131 VBDEBUG(("Unable to read GPT data\n"));
132 shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR;
133 goto bad_gpt;
134 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700135
Randall Spangler7993f252013-01-29 15:01:12 -0800136 /* Initialize GPT library */
137 if (GPT_SUCCESS != GptInit(&gpt)) {
138 VBDEBUG(("Error parsing GPT\n"));
139 shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR;
140 goto bad_gpt;
141 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700142
Randall Spangler7993f252013-01-29 15:01:12 -0800143 /* Allocate kernel header buffers */
144 kbuf = (uint8_t*)VbExMalloc(KBUF_SIZE);
145 if (!kbuf)
146 goto bad_gpt;
Randall Spanglerd1836442010-06-10 09:59:04 -0700147
Gwendal Grignoue2e14ae2015-04-27 09:46:52 -0700148 /* Loop over candidate kernel partitions */
149 while (GPT_SUCCESS ==
150 GptNextKernelEntry(&gpt, &part_start, &part_size)) {
Randall Spangler7993f252013-01-29 15:01:12 -0800151 VbSharedDataKernelPart *shpart = NULL;
152 VbKeyBlockHeader *key_block;
153 VbKernelPreambleHeader *preamble;
154 RSAPublicKey *data_key = NULL;
Randall Spangler4184e622014-10-08 16:41:01 -0700155 VbExStream_t stream = NULL;
Randall Spangler7993f252013-01-29 15:01:12 -0800156 uint64_t key_version;
157 uint32_t combined_version;
158 uint64_t body_offset;
Randall Spangler7993f252013-01-29 15:01:12 -0800159 int key_block_valid = 1;
Randall Spanglerd1836442010-06-10 09:59:04 -0700160
Randall Spangler7993f252013-01-29 15:01:12 -0800161 VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n",
162 part_start, part_size));
Randall Spanglerd1836442010-06-10 09:59:04 -0700163
Randall Spangler7993f252013-01-29 15:01:12 -0800164 /*
165 * Set up tracking for this partition. This wraps around if
166 * called many times, so initialize the partition entry each
167 * time.
168 */
169 shpart = shcall->parts + (shcall->kernel_parts_found
Gwendal Grignoue2e14ae2015-04-27 09:46:52 -0700170 & (VBSD_MAX_KERNEL_PARTS - 1));
Randall Spangler664096b2016-10-13 16:16:41 -0700171 memset(shpart, 0, sizeof(VbSharedDataKernelPart));
Randall Spangler7993f252013-01-29 15:01:12 -0800172 shpart->sector_start = part_start;
173 shpart->sector_count = part_size;
174 /*
175 * TODO: GPT partitions start at 1, but cgptlib starts them at
176 * 0. Adjust here, until cgptlib is fixed.
177 */
178 shpart->gpt_index = (uint8_t)(gpt.current_kernel + 1);
179 shcall->kernel_parts_found++;
Randall Spangler695cd162010-06-15 23:38:23 -0700180
Randall Spangler7993f252013-01-29 15:01:12 -0800181 /* Found at least one kernel partition. */
182 found_partitions++;
Randall Spangler17c71262011-03-18 11:24:27 -0700183
Randall Spangler4184e622014-10-08 16:41:01 -0700184 /* Set up the stream */
185 if (VbExStreamOpen(params->disk_handle,
186 part_start, part_size, &stream)) {
187 VBDEBUG(("Partition error getting stream.\n"));
Randall Spangler7993f252013-01-29 15:01:12 -0800188 shpart->check_result = VBSD_LKP_CHECK_TOO_SMALL;
189 goto bad_kernel;
190 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700191
Randall Spangler4184e622014-10-08 16:41:01 -0700192 if (0 != VbExStreamRead(stream, KBUF_SIZE, kbuf)) {
Randall Spangler7993f252013-01-29 15:01:12 -0800193 VBDEBUG(("Unable to read start of partition.\n"));
194 shpart->check_result = VBSD_LKP_CHECK_READ_START;
195 goto bad_kernel;
196 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700197
Randall Spangler7993f252013-01-29 15:01:12 -0800198 /* Verify the key block. */
199 key_block = (VbKeyBlockHeader*)kbuf;
200 if (0 != KeyBlockVerify(key_block, KBUF_SIZE,
201 kernel_subkey, 0)) {
202 VBDEBUG(("Verifying key block signature failed.\n"));
203 shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_SIG;
204 key_block_valid = 0;
Randall Spangler17c71262011-03-18 11:24:27 -0700205
Randall Spangler7993f252013-01-29 15:01:12 -0800206 /* If not in developer mode, this kernel is bad. */
207 if (kBootDev != boot_mode)
208 goto bad_kernel;
Randall Spanglerd1836442010-06-10 09:59:04 -0700209
Randall Spangler7993f252013-01-29 15:01:12 -0800210 /*
Bill Richardson9c647ef2015-03-03 10:39:08 -0800211 * In developer mode, we can explicitly disallow
Randall Spangler7993f252013-01-29 15:01:12 -0800212 * self-signed kernels
213 */
214 if (require_official_os) {
215 VBDEBUG(("Self-signed kernels not enabled.\n"));
216 shpart->check_result =
217 VBSD_LKP_CHECK_SELF_SIGNED;
218 goto bad_kernel;
219 }
Randall Spangler640fb512011-03-03 10:11:17 -0800220
Randall Spangler7993f252013-01-29 15:01:12 -0800221 /*
222 * Allow the kernel if the SHA-512 hash of the key
223 * block is valid.
224 */
225 if (0 != KeyBlockVerify(key_block, KBUF_SIZE,
226 kernel_subkey, 1)) {
227 VBDEBUG(("Verifying key block hash failed.\n"));
228 shpart->check_result =
229 VBSD_LKP_CHECK_KEY_BLOCK_HASH;
230 goto bad_kernel;
231 }
232 }
Bill Richardsonfa9d7782011-11-09 09:11:34 -0800233
Randall Spangler7993f252013-01-29 15:01:12 -0800234 /* Check the key block flags against the current boot mode. */
235 if (!(key_block->key_block_flags &
236 (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 :
237 KEY_BLOCK_FLAG_DEVELOPER_0))) {
238 VBDEBUG(("Key block developer flag mismatch.\n"));
239 shpart->check_result = VBSD_LKP_CHECK_DEV_MISMATCH;
240 key_block_valid = 0;
241 }
242 if (!(key_block->key_block_flags &
243 (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 :
244 KEY_BLOCK_FLAG_RECOVERY_0))) {
245 VBDEBUG(("Key block recovery flag mismatch.\n"));
246 shpart->check_result = VBSD_LKP_CHECK_REC_MISMATCH;
247 key_block_valid = 0;
248 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700249
Randall Spangler7993f252013-01-29 15:01:12 -0800250 /* Check for rollback of key version except in recovery mode. */
251 key_version = key_block->data_key.key_version;
252 if (kBootRecovery != boot_mode) {
253 if (key_version < (shared->kernel_version_tpm >> 16)) {
254 VBDEBUG(("Key version too old.\n"));
255 shpart->check_result =
256 VBSD_LKP_CHECK_KEY_ROLLBACK;
257 key_block_valid = 0;
258 }
259 if (key_version > 0xFFFF) {
260 /*
261 * Key version is stored in 16 bits in the TPM,
262 * so key versions greater than 0xFFFF can't be
263 * stored properly.
264 */
265 VBDEBUG(("Key version > 0xFFFF.\n"));
266 shpart->check_result =
267 VBSD_LKP_CHECK_KEY_ROLLBACK;
268 key_block_valid = 0;
269 }
270 }
Randall Spangler640fb512011-03-03 10:11:17 -0800271
Randall Spangler7993f252013-01-29 15:01:12 -0800272 /* If not in developer mode, key block required to be valid. */
273 if (kBootDev != boot_mode && !key_block_valid) {
274 VBDEBUG(("Key block is invalid.\n"));
275 goto bad_kernel;
276 }
Randall Spangler640fb512011-03-03 10:11:17 -0800277
Randall Spangler946abf12016-04-15 14:49:40 -0700278
279 /* If in developer mode and using key hash, check it */
280 if ((kBootDev == boot_mode) &&
281 params->fwmp &&
282 (params->fwmp->flags & FWMP_DEV_USE_KEY_HASH)) {
283 VbPublicKey *key = &key_block->data_key;
284 uint8_t *buf = ((uint8_t *)key) + key->key_offset;
285 uint64_t buflen = key->key_size;
Randall Spangler7c3ae422016-05-11 13:50:18 -0700286 uint8_t digest[VB2_SHA256_DIGEST_SIZE];
Randall Spangler946abf12016-04-15 14:49:40 -0700287
288 VBDEBUG(("Checking developer key hash.\n"));
Randall Spangler7c3ae422016-05-11 13:50:18 -0700289 vb2_digest_buffer(buf, buflen, VB2_HASH_SHA256,
290 digest, sizeof(digest));
Randall Spangler946abf12016-04-15 14:49:40 -0700291 if (0 != SafeMemcmp(digest, params->fwmp->dev_key_hash,
Randall Spangler7c3ae422016-05-11 13:50:18 -0700292 VB2_SHA256_DIGEST_SIZE)) {
Randall Spangler946abf12016-04-15 14:49:40 -0700293 int i;
294
295 VBDEBUG(("Wrong developer key hash.\n"));
296 VBDEBUG(("Want: "));
Randall Spangler7c3ae422016-05-11 13:50:18 -0700297 for (i = 0; i < VB2_SHA256_DIGEST_SIZE; i++)
Randall Spangler946abf12016-04-15 14:49:40 -0700298 VBDEBUG(("%02x",
299 params->fwmp->dev_key_hash[i]));
300 VBDEBUG(("\nGot: "));
Randall Spangler7c3ae422016-05-11 13:50:18 -0700301 for (i = 0; i < VB2_SHA256_DIGEST_SIZE; i++)
Randall Spangler946abf12016-04-15 14:49:40 -0700302 VBDEBUG(("%02x", digest[i]));
303 VBDEBUG(("\n"));
304
Randall Spangler946abf12016-04-15 14:49:40 -0700305 goto bad_kernel;
306 }
Randall Spangler946abf12016-04-15 14:49:40 -0700307 }
308
Randall Spangler7993f252013-01-29 15:01:12 -0800309 /* Get key for preamble/data verification from the key block. */
310 data_key = PublicKeyToRSA(&key_block->data_key);
311 if (!data_key) {
312 VBDEBUG(("Data key bad.\n"));
313 shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE;
314 goto bad_kernel;
315 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700316
Randall Spangler7993f252013-01-29 15:01:12 -0800317 /* Verify the preamble, which follows the key block */
318 preamble = (VbKernelPreambleHeader *)
319 (kbuf + key_block->key_block_size);
320 if ((0 != VerifyKernelPreamble(
321 preamble,
322 KBUF_SIZE - key_block->key_block_size,
323 data_key))) {
324 VBDEBUG(("Preamble verification failed.\n"));
325 shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE;
326 goto bad_kernel;
327 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700328
Randall Spangler7993f252013-01-29 15:01:12 -0800329 /*
330 * If the key block is valid and we're not in recovery mode,
331 * check for rollback of the kernel version.
332 */
333 combined_version = (uint32_t)(
334 (key_version << 16) |
335 (preamble->kernel_version & 0xFFFF));
336 shpart->combined_version = combined_version;
337 if (key_block_valid && kBootRecovery != boot_mode) {
338 if (combined_version < shared->kernel_version_tpm) {
339 VBDEBUG(("Kernel version too low.\n"));
340 shpart->check_result =
341 VBSD_LKP_CHECK_KERNEL_ROLLBACK;
342 /*
343 * If not in developer mode, kernel version
344 * must be valid.
345 */
346 if (kBootDev != boot_mode)
347 goto bad_kernel;
348 }
349 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700350
Randall Spangler7993f252013-01-29 15:01:12 -0800351 VBDEBUG(("Kernel preamble is good.\n"));
352 shpart->check_result = VBSD_LKP_CHECK_PREAMBLE_VALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700353
Randall Spangler7993f252013-01-29 15:01:12 -0800354 /* Check for lowest version from a valid header. */
355 if (key_block_valid && lowest_version > combined_version)
356 lowest_version = combined_version;
357 else {
358 VBDEBUG(("Key block valid: %d\n", key_block_valid));
359 VBDEBUG(("Combined version: %u\n",
Gwendal Grignoue2e14ae2015-04-27 09:46:52 -0700360 (unsigned) combined_version));
Randall Spangler7993f252013-01-29 15:01:12 -0800361 }
Randall Spangler695cd162010-06-15 23:38:23 -0700362
Randall Spangler7993f252013-01-29 15:01:12 -0800363 /*
364 * If we already have a good kernel, no need to read another
365 * one; we only needed to look at the versions to check for
366 * rollback. So skip to the next kernel preamble.
367 */
Randall Spangler4184e622014-10-08 16:41:01 -0700368 if (-1 != good_partition) {
369 VbExStreamClose(stream);
370 stream = NULL;
Randall Spangler7993f252013-01-29 15:01:12 -0800371 continue;
Randall Spangler4184e622014-10-08 16:41:01 -0700372 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700373
Randall Spangler7993f252013-01-29 15:01:12 -0800374 body_offset = key_block->key_block_size +
375 preamble->preamble_size;
Randall Spangler4184e622014-10-08 16:41:01 -0700376
377 /*
378 * Make sure the kernel starts at or before what we already
379 * read into kbuf.
380 *
381 * We could deal with a larger offset by reading and discarding
382 * the data in between the vblock and the kernel data.
383 */
384 if (body_offset > KBUF_SIZE) {
Randall Spangler7993f252013-01-29 15:01:12 -0800385 shpart->check_result = VBSD_LKP_CHECK_BODY_OFFSET;
Randall Spangler4184e622014-10-08 16:41:01 -0700386 VBDEBUG(("Kernel body offset is %d > 64KB.\n",
387 (int)body_offset));
Randall Spangler7993f252013-01-29 15:01:12 -0800388 goto bad_kernel;
389 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700390
Randall Spangler7993f252013-01-29 15:01:12 -0800391 if (!params->kernel_buffer) {
392 /* Get kernel load address and size from the header. */
393 params->kernel_buffer =
394 (void *)((long)preamble->body_load_address);
Randall Spangler4184e622014-10-08 16:41:01 -0700395 params->kernel_buffer_size =
396 preamble->body_signature.data_size;
397 } else if (preamble->body_signature.data_size >
398 params->kernel_buffer_size) {
399 VBDEBUG(("Kernel body doesn't fit in memory.\n"));
400 shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_MEM;
Randall Spangler7993f252013-01-29 15:01:12 -0800401 goto bad_kernel;
402 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700403
Randall Spangler4184e622014-10-08 16:41:01 -0700404 /*
405 * Body signature data size is 64 bit and toread is 32 bit so
406 * this could technically cause us to read less data. That's
407 * fine, because a 4 GB kernel is implausible, and if we did
408 * have one that big, we'd simply read too little data and fail
409 * to verify it.
410 */
411 body_toread = preamble->body_signature.data_size;
412 body_readptr = params->kernel_buffer;
413
414 /*
415 * If we've already read part of the kernel, copy that to the
416 * beginning of the kernel buffer.
417 */
418 if (body_offset < KBUF_SIZE) {
419 uint32_t body_copied = KBUF_SIZE - body_offset;
420
421 /* If the kernel is tiny, don't over-copy */
422 if (body_copied > body_toread)
423 body_copied = body_toread;
424
Randall Spangler664096b2016-10-13 16:16:41 -0700425 memcpy(body_readptr, kbuf + body_offset, body_copied);
Randall Spangler4184e622014-10-08 16:41:01 -0700426 body_toread -= body_copied;
427 body_readptr += body_copied;
428 }
429
Randall Spangler7993f252013-01-29 15:01:12 -0800430 /* Read the kernel data */
Randall Spangler4184e622014-10-08 16:41:01 -0700431 if (body_toread &&
432 0 != VbExStreamRead(stream, body_toread, body_readptr)) {
Randall Spangler7993f252013-01-29 15:01:12 -0800433 VBDEBUG(("Unable to read kernel data.\n"));
Randall Spangler7993f252013-01-29 15:01:12 -0800434 shpart->check_result = VBSD_LKP_CHECK_READ_DATA;
435 goto bad_kernel;
436 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700437
Randall Spangler4184e622014-10-08 16:41:01 -0700438 /* Close the stream; we're done with it */
439 VbExStreamClose(stream);
440 stream = NULL;
441
Randall Spangler7993f252013-01-29 15:01:12 -0800442 /* Verify kernel data */
443 if (0 != VerifyData((const uint8_t *)params->kernel_buffer,
444 params->kernel_buffer_size,
445 &preamble->body_signature, data_key)) {
446 VBDEBUG(("Kernel data verification failed.\n"));
447 shpart->check_result = VBSD_LKP_CHECK_VERIFY_DATA;
448 goto bad_kernel;
449 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700450
Randall Spangler7993f252013-01-29 15:01:12 -0800451 /* Done with the kernel signing key, so can free it now */
452 RSAPublicKeyFree(data_key);
453 data_key = NULL;
Randall Spanglerd1836442010-06-10 09:59:04 -0700454
Randall Spangler7993f252013-01-29 15:01:12 -0800455 /*
456 * If we're still here, the kernel is valid. Save the first
457 * good partition we find; that's the one we'll boot.
458 */
459 VBDEBUG(("Partition is good.\n"));
460 shpart->check_result = VBSD_LKP_CHECK_KERNEL_GOOD;
461 if (key_block_valid)
462 shpart->flags |= VBSD_LKP_FLAG_KEY_BLOCK_VALID;
Randall Spangler17c71262011-03-18 11:24:27 -0700463
Randall Spangler7993f252013-01-29 15:01:12 -0800464 good_partition_key_block_valid = key_block_valid;
465 /*
466 * TODO: GPT partitions start at 1, but cgptlib starts them at
467 * 0. Adjust here, until cgptlib is fixed.
468 */
469 good_partition = gpt.current_kernel + 1;
470 params->partition_number = gpt.current_kernel + 1;
471 GetCurrentKernelUniqueGuid(&gpt, &params->partition_guid);
472 /*
473 * TODO: GetCurrentKernelUniqueGuid() should take a destination
474 * size, or the dest should be a struct, so we know it's big
475 * enough.
476 */
Randall Spangler7993f252013-01-29 15:01:12 -0800477 params->bootloader_address = preamble->bootloader_address;
478 params->bootloader_size = preamble->bootloader_size;
Furquan Shaikhb7d1f032015-02-03 16:28:31 -0800479 if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS)
480 params->flags = preamble->flags;
Randall Spangler741d2b22010-08-20 16:37:12 -0700481
Patrick Georgiebf886b2015-02-10 14:58:28 +0100482 /* Update GPT to note this is the kernel we're trying.
483 * But not when we assume that the boot process may
484 * not complete for valid reasons (eg. early shutdown).
485 */
486 if (!(shared->flags & VBSD_NOFAIL_BOOT))
487 GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_TRY);
Randall Spangler741d2b22010-08-20 16:37:12 -0700488
Randall Spangler7993f252013-01-29 15:01:12 -0800489 /*
490 * If we're in recovery mode or we're about to boot a
491 * dev-signed kernel, there's no rollback protection, so we can
492 * stop at the first valid kernel.
493 */
494 if (kBootRecovery == boot_mode || !key_block_valid) {
495 VBDEBUG(("In recovery mode or dev-signed kernel\n"));
496 break;
497 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700498
Randall Spangler7993f252013-01-29 15:01:12 -0800499 /*
500 * Otherwise, we do care about the key index in the TPM. If
501 * the good partition's key version is the same as the tpm,
502 * then the TPM doesn't need updating; we can stop now.
503 * Otherwise, we'll check all the other headers to see if they
504 * contain a newer key.
505 */
506 if (combined_version == shared->kernel_version_tpm) {
507 VBDEBUG(("Same kernel version\n"));
508 break;
509 }
Randall Spangler741d2b22010-08-20 16:37:12 -0700510
Randall Spangler7993f252013-01-29 15:01:12 -0800511 /* Continue, so that we skip the error handling code below */
512 continue;
Randall Spangler741d2b22010-08-20 16:37:12 -0700513
Gwendal Grignoue2e14ae2015-04-27 09:46:52 -0700514bad_kernel:
Randall Spangler7993f252013-01-29 15:01:12 -0800515 /* Handle errors parsing this kernel */
Randall Spangler4184e622014-10-08 16:41:01 -0700516 if (NULL != stream)
517 VbExStreamClose(stream);
Randall Spangler7993f252013-01-29 15:01:12 -0800518 if (NULL != data_key)
519 RSAPublicKeyFree(data_key);
Randall Spangler741d2b22010-08-20 16:37:12 -0700520
Randall Spangler7993f252013-01-29 15:01:12 -0800521 VBDEBUG(("Marking kernel as invalid.\n"));
522 GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD);
Randall Spangler741d2b22010-08-20 16:37:12 -0700523
524
Gwendal Grignoue2e14ae2015-04-27 09:46:52 -0700525 } /* while(GptNextKernelEntry) */
Randall Spangler49cb0d32013-01-29 14:28:16 -0800526
Gwendal Grignoue2e14ae2015-04-27 09:46:52 -0700527bad_gpt:
Randall Spanglerd1836442010-06-10 09:59:04 -0700528
Randall Spangler7993f252013-01-29 15:01:12 -0800529 /* Free kernel buffer */
530 if (kbuf)
531 VbExFree(kbuf);
Randall Spanglerd1836442010-06-10 09:59:04 -0700532
Randall Spangler7993f252013-01-29 15:01:12 -0800533 /* Write and free GPT data */
534 WriteAndFreeGptData(params->disk_handle, &gpt);
Randall Spanglerd1836442010-06-10 09:59:04 -0700535
Randall Spangler7993f252013-01-29 15:01:12 -0800536 /* Handle finding a good partition */
537 if (good_partition >= 0) {
538 VBDEBUG(("Good_partition >= 0\n"));
539 shcall->check_result = VBSD_LKC_CHECK_GOOD_PARTITION;
540 shared->kernel_version_lowest = lowest_version;
541 /*
542 * Sanity check - only store a new TPM version if we found one.
543 * If lowest_version is still at its initial value, we didn't
544 * find one; for example, we're in developer mode and just
545 * didn't look.
546 */
547 if (lowest_version != LOWEST_TPM_VERSION &&
548 lowest_version > shared->kernel_version_tpm)
549 shared->kernel_version_tpm = lowest_version;
Randall Spanglerd1836442010-06-10 09:59:04 -0700550
Randall Spangler7993f252013-01-29 15:01:12 -0800551 /* Success! */
552 retval = VBERROR_SUCCESS;
553 } else if (found_partitions > 0) {
554 shcall->check_result = VBSD_LKC_CHECK_INVALID_PARTITIONS;
555 recovery = VBNV_RECOVERY_RW_INVALID_OS;
556 retval = VBERROR_INVALID_KERNEL_FOUND;
557 } else {
558 shcall->check_result = VBSD_LKC_CHECK_NO_PARTITIONS;
559 recovery = VBNV_RECOVERY_RW_NO_OS;
560 retval = VBERROR_NO_KERNEL_FOUND;
561 }
Randall Spanglerd1836442010-06-10 09:59:04 -0700562
Gwendal Grignoue2e14ae2015-04-27 09:46:52 -0700563LoadKernelExit:
Randall Spangler640fb512011-03-03 10:11:17 -0800564
Randall Spangler7993f252013-01-29 15:01:12 -0800565 /* Store recovery request, if any */
566 VbNvSet(vnc, VBNV_RECOVERY_REQUEST, VBERROR_SUCCESS != retval ?
567 recovery : VBNV_RECOVERY_NOT_REQUESTED);
Randall Spangler640fb512011-03-03 10:11:17 -0800568
Randall Spangler7993f252013-01-29 15:01:12 -0800569 /*
570 * If LoadKernel() was called with bad parameters, shcall may not be
571 * initialized.
572 */
573 if (shcall)
574 shcall->return_code = (uint8_t)retval;
Randall Spangler17c71262011-03-18 11:24:27 -0700575
Randall Spangler7993f252013-01-29 15:01:12 -0800576 /* Save whether the good partition's key block was fully verified */
577 if (good_partition_key_block_valid)
578 shared->flags |= VBSD_KERNEL_KEY_VERIFIED;
Randall Spangler17c71262011-03-18 11:24:27 -0700579
Randall Spangler7993f252013-01-29 15:01:12 -0800580 /* Store how much shared data we used, if any */
581 params->shared_data_size = shared->data_used;
Randall Spangler95c40312011-03-09 15:54:16 -0800582
Simon Glass527ba812013-07-25 08:48:47 -0600583 if (free_kernel_subkey)
584 VbExFree(kernel_subkey);
585
Randall Spangler7993f252013-01-29 15:01:12 -0800586 return retval;
Randall Spanglerd1836442010-06-10 09:59:04 -0700587}