17993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2d183644564ec27c106a3eb1931f565fae167a058Randall Spangler * Use of this source code is governed by a BSD-style license that can be 3d183644564ec27c106a3eb1931f565fae167a058Randall Spangler * found in the LICENSE file. 4d183644564ec27c106a3eb1931f565fae167a058Randall Spangler * 5d183644564ec27c106a3eb1931f565fae167a058Randall Spangler * Functions for loading a kernel from disk. 6d183644564ec27c106a3eb1931f565fae167a058Randall Spangler * (Firmware portion) 7d183644564ec27c106a3eb1931f565fae167a058Randall Spangler */ 8d183644564ec27c106a3eb1931f565fae167a058Randall Spangler 90c3ba249abb1dc60f5ebabccf84ff13206440b83Bill Richardson#include "sysincludes.h" 101b1998dff0002f20b3f27a21e6e79d8951e64684Randall Spangler 11d183644564ec27c106a3eb1931f565fae167a058Randall Spangler#include "cgptlib.h" 125deb67f22507481cf5cb8f991976a9969fa90a22Bill Richardson#include "cgptlib_internal.h" 13527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass#include "region.h" 14527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass#include "gbb_access.h" 1595c4031ce903258036beeed0705d25c7e9d25da0Randall Spangler#include "gbb_header.h" 167c2beb08380410ca6847abdac23e11ded2d1b625Dan Ehrenberg#include "gpt_misc.h" 17d183644564ec27c106a3eb1931f565fae167a058Randall Spangler#include "load_kernel_fw.h" 18d183644564ec27c106a3eb1931f565fae167a058Randall Spangler#include "utility.h" 19e49e8af65fce38da7a308305566f8a14f102254aRandall Spangler#include "vboot_api.h" 2083c88cfa6920711b8a7823e1e3fc0efe8b71a04cRandall Spangler#include "vboot_common.h" 21e49e8af65fce38da7a308305566f8a14f102254aRandall Spangler#include "vboot_kernel.h" 22e49e8af65fce38da7a308305566f8a14f102254aRandall Spangler 23d183644564ec27c106a3eb1931f565fae167a058Randall Spangler#define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */ 2455db6a67176a4933427d2ee556180f6e814f60d9Stefan Reinauer#define LOWEST_TPM_VERSION 0xffffffff 25d183644564ec27c106a3eb1931f565fae167a058Randall Spangler 26640fb51d866e7ac8a92f61a2f69145bfe6b13699Randall Spanglertypedef enum BootMode { 277993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler kBootRecovery = 0, /* Recovery firmware, any dev switch position */ 287993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler kBootNormal = 1, /* Normal boot - kernel must be verified */ 297993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler kBootDev = 2 /* Developer boot - self-signed kernel ok */ 30640fb51d866e7ac8a92f61a2f69145bfe6b13699Randall Spangler} BootMode; 31640fb51d866e7ac8a92f61a2f69145bfe6b13699Randall Spangler 32527ba810eff4006cf69579f6b96cb4350cb1e189Simon GlassVbError_t LoadKernel(LoadKernelParams *params, VbCommonParams *cparams) 337993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler{ 347993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VbSharedDataHeader *shared = 357993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler (VbSharedDataHeader *)params->shared_data_blob; 367993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VbSharedDataKernelCall *shcall = NULL; 377993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VbNvContext* vnc = params->nv_context; 38527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass VbPublicKey* kernel_subkey = NULL; 39527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass int free_kernel_subkey = 0; 407993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler GptData gpt; 417993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler uint64_t part_start, part_size; 427993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler uint64_t blba; 437993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler uint64_t kbuf_sectors; 447993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler uint8_t* kbuf = NULL; 457993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler int found_partitions = 0; 467993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler int good_partition = -1; 477993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler int good_partition_key_block_valid = 0; 487993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler uint32_t lowest_version = LOWEST_TPM_VERSION; 497993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler int rec_switch, dev_switch; 507993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler BootMode boot_mode; 517993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler uint32_t require_official_os = 0; 524184e626336fa8d794a21208387226f154d77d0fRandall Spangler uint32_t body_toread; 534184e626336fa8d794a21208387226f154d77d0fRandall Spangler uint8_t *body_readptr; 547993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 557993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VbError_t retval = VBERROR_UNKNOWN; 567993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler int recovery = VBNV_RECOVERY_LK_UNSPECIFIED; 577993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 587993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Sanity Checks */ 597993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (!params->bytes_per_lba || 603f4d8d05ba4e32990c8584bd47cdf082d4604232Dan Ehrenberg !params->streaming_lba_count) { 617993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("LoadKernel() called with invalid params\n")); 627993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler retval = VBERROR_INVALID_PARAMETER; 637993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto LoadKernelExit; 647993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 657993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 667993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Clear output params in case we fail */ 677993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler params->partition_number = 0; 687993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler params->bootloader_address = 0; 697993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler params->bootloader_size = 0; 70b7d1f03e368b146d11eab511cd6a573a528bc728Furquan Shaikh params->flags = 0; 717993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 727993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Calculate switch positions and boot mode */ 737993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0); 747993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0); 757993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (rec_switch) { 767993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler boot_mode = kBootRecovery; 777993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } else if (dev_switch) { 787993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler boot_mode = kBootDev; 797993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VbNvGet(vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &require_official_os); 807993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } else { 817993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler boot_mode = kBootNormal; 827993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 837993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 847993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 857993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * Set up tracking for this call. This wraps around if called many 867993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * times, so we need to initialize the call entry each time. 877993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 887993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shcall = shared->lk_calls + (shared->lk_call_count 897993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler & (VBSD_MAX_KERNEL_CALLS - 1)); 907993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler Memset(shcall, 0, sizeof(VbSharedDataKernelCall)); 917993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shcall->boot_flags = (uint32_t)params->boot_flags; 927993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shcall->boot_mode = boot_mode; 937993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shcall->sector_size = (uint32_t)params->bytes_per_lba; 943f4d8d05ba4e32990c8584bd47cdf082d4604232Dan Ehrenberg shcall->sector_count = params->streaming_lba_count; 957993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shared->lk_call_count++; 967993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 977993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Initialization */ 987993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler blba = params->bytes_per_lba; 997993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler kbuf_sectors = KBUF_SIZE / blba; 1007993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (0 == kbuf_sectors) { 1017993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n")); 1027993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler retval = VBERROR_INVALID_PARAMETER; 1037993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto LoadKernelExit; 1047993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 1057993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 1067993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (kBootRecovery == boot_mode) { 1077993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Use the recovery key to verify the kernel */ 108527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass retval = VbGbbReadRecoveryKey(cparams, &kernel_subkey); 109527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass if (VBERROR_SUCCESS != retval) 110527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass goto LoadKernelExit; 111527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass free_kernel_subkey = 1; 1127993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } else { 1137993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Use the kernel subkey passed from LoadFirmware(). */ 1147993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler kernel_subkey = &shared->kernel_subkey; 1157993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 1167993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 1177993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Read GPT data */ 1187993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler gpt.sector_bytes = (uint32_t)blba; 1193f4d8d05ba4e32990c8584bd47cdf082d4604232Dan Ehrenberg gpt.streaming_drive_sectors = params->streaming_lba_count; 1203f4d8d05ba4e32990c8584bd47cdf082d4604232Dan Ehrenberg gpt.gpt_drive_sectors = params->gpt_lba_count; 1213f4d8d05ba4e32990c8584bd47cdf082d4604232Dan Ehrenberg gpt.flags = params->boot_flags & BOOT_FLAG_EXTERNAL_GPT 1223f4d8d05ba4e32990c8584bd47cdf082d4604232Dan Ehrenberg ? GPT_FLAG_EXTERNAL : 0; 1237993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (0 != AllocAndReadGptData(params->disk_handle, &gpt)) { 1247993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Unable to read GPT data\n")); 1257993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR; 1267993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_gpt; 1277993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 1287993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 1297993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Initialize GPT library */ 1307993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (GPT_SUCCESS != GptInit(&gpt)) { 1317993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Error parsing GPT\n")); 1327993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR; 1337993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_gpt; 1347993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 1357993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 1367993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Allocate kernel header buffers */ 1377993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler kbuf = (uint8_t*)VbExMalloc(KBUF_SIZE); 1387993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (!kbuf) 1397993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_gpt; 1407993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 1417993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Loop over candidate kernel partitions */ 1427993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler while (GPT_SUCCESS == 1437993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler GptNextKernelEntry(&gpt, &part_start, &part_size)) { 1447993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VbSharedDataKernelPart *shpart = NULL; 1457993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VbKeyBlockHeader *key_block; 1467993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VbKernelPreambleHeader *preamble; 1477993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler RSAPublicKey *data_key = NULL; 1484184e626336fa8d794a21208387226f154d77d0fRandall Spangler VbExStream_t stream = NULL; 1497993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler uint64_t key_version; 1507993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler uint32_t combined_version; 1517993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler uint64_t body_offset; 1527993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler int key_block_valid = 1; 1537993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 1547993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", 1557993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler part_start, part_size)); 1567993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 1577993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 1587993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * Set up tracking for this partition. This wraps around if 1597993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * called many times, so initialize the partition entry each 1607993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * time. 1617993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 1627993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart = shcall->parts + (shcall->kernel_parts_found 1637993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler & (VBSD_MAX_KERNEL_PARTS - 1)); 1647993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler Memset(shpart, 0, sizeof(VbSharedDataKernelPart)); 1657993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->sector_start = part_start; 1667993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->sector_count = part_size; 1677993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 1687993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * TODO: GPT partitions start at 1, but cgptlib starts them at 1697993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * 0. Adjust here, until cgptlib is fixed. 1707993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 1717993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->gpt_index = (uint8_t)(gpt.current_kernel + 1); 1727993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shcall->kernel_parts_found++; 1737993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 1747993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Found at least one kernel partition. */ 1757993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler found_partitions++; 1767993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 1774184e626336fa8d794a21208387226f154d77d0fRandall Spangler /* Set up the stream */ 1784184e626336fa8d794a21208387226f154d77d0fRandall Spangler if (VbExStreamOpen(params->disk_handle, 1794184e626336fa8d794a21208387226f154d77d0fRandall Spangler part_start, part_size, &stream)) { 1804184e626336fa8d794a21208387226f154d77d0fRandall Spangler VBDEBUG(("Partition error getting stream.\n")); 1817993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = VBSD_LKP_CHECK_TOO_SMALL; 1827993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_kernel; 1837993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 1847993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 1854184e626336fa8d794a21208387226f154d77d0fRandall Spangler if (0 != VbExStreamRead(stream, KBUF_SIZE, kbuf)) { 1867993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Unable to read start of partition.\n")); 1877993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = VBSD_LKP_CHECK_READ_START; 1887993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_kernel; 1897993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 190d183644564ec27c106a3eb1931f565fae167a058Randall Spangler 1917993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Verify the key block. */ 1927993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler key_block = (VbKeyBlockHeader*)kbuf; 1937993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (0 != KeyBlockVerify(key_block, KBUF_SIZE, 1947993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler kernel_subkey, 0)) { 1957993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Verifying key block signature failed.\n")); 1967993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_SIG; 1977993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler key_block_valid = 0; 1987993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 1997993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* If not in developer mode, this kernel is bad. */ 2007993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (kBootDev != boot_mode) 2017993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_kernel; 2027993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 2037993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 2047993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * In developer mode, we can explictly disallow 2057993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * self-signed kernels 2067993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 2077993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (require_official_os) { 2087993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Self-signed kernels not enabled.\n")); 2097993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = 2107993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBSD_LKP_CHECK_SELF_SIGNED; 2117993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_kernel; 2127993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 2137993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 2147993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 2157993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * Allow the kernel if the SHA-512 hash of the key 2167993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * block is valid. 2177993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 2187993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (0 != KeyBlockVerify(key_block, KBUF_SIZE, 2197993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler kernel_subkey, 1)) { 2207993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Verifying key block hash failed.\n")); 2217993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = 2227993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBSD_LKP_CHECK_KEY_BLOCK_HASH; 2237993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_kernel; 2247993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 2257993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 2267993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 2277993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Check the key block flags against the current boot mode. */ 2287993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (!(key_block->key_block_flags & 2297993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 : 2307993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler KEY_BLOCK_FLAG_DEVELOPER_0))) { 2317993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Key block developer flag mismatch.\n")); 2327993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = VBSD_LKP_CHECK_DEV_MISMATCH; 2337993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler key_block_valid = 0; 2347993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 2357993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (!(key_block->key_block_flags & 2367993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 : 2377993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler KEY_BLOCK_FLAG_RECOVERY_0))) { 2387993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Key block recovery flag mismatch.\n")); 2397993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = VBSD_LKP_CHECK_REC_MISMATCH; 2407993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler key_block_valid = 0; 2417993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 2427993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 2437993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Check for rollback of key version except in recovery mode. */ 2447993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler key_version = key_block->data_key.key_version; 2457993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (kBootRecovery != boot_mode) { 2467993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (key_version < (shared->kernel_version_tpm >> 16)) { 2477993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Key version too old.\n")); 2487993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = 2497993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBSD_LKP_CHECK_KEY_ROLLBACK; 2507993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler key_block_valid = 0; 2517993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 2527993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (key_version > 0xFFFF) { 2537993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 2547993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * Key version is stored in 16 bits in the TPM, 2557993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * so key versions greater than 0xFFFF can't be 2567993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * stored properly. 2577993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 2587993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Key version > 0xFFFF.\n")); 2597993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = 2607993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBSD_LKP_CHECK_KEY_ROLLBACK; 2617993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler key_block_valid = 0; 2627993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 2637993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 2647993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 2657993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* If not in developer mode, key block required to be valid. */ 2667993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (kBootDev != boot_mode && !key_block_valid) { 2677993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Key block is invalid.\n")); 2687993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_kernel; 2697993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 2707993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 2717993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Get key for preamble/data verification from the key block. */ 2727993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler data_key = PublicKeyToRSA(&key_block->data_key); 2737993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (!data_key) { 2747993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Data key bad.\n")); 2757993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE; 2767993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_kernel; 2777993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 2787993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 2797993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Verify the preamble, which follows the key block */ 2807993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler preamble = (VbKernelPreambleHeader *) 2817993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler (kbuf + key_block->key_block_size); 2827993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if ((0 != VerifyKernelPreamble( 2837993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler preamble, 2847993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler KBUF_SIZE - key_block->key_block_size, 2857993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler data_key))) { 2867993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Preamble verification failed.\n")); 2877993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE; 2887993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_kernel; 2897993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 2907993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 2917993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 2927993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * If the key block is valid and we're not in recovery mode, 2937993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * check for rollback of the kernel version. 2947993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 2957993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler combined_version = (uint32_t)( 2967993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler (key_version << 16) | 2977993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler (preamble->kernel_version & 0xFFFF)); 2987993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->combined_version = combined_version; 2997993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (key_block_valid && kBootRecovery != boot_mode) { 3007993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (combined_version < shared->kernel_version_tpm) { 3017993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Kernel version too low.\n")); 3027993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = 3037993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBSD_LKP_CHECK_KERNEL_ROLLBACK; 3047993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 3057993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * If not in developer mode, kernel version 3067993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * must be valid. 3077993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 3087993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (kBootDev != boot_mode) 3097993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_kernel; 3107993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 3117993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 3127993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 3137993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Kernel preamble is good.\n")); 3147993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = VBSD_LKP_CHECK_PREAMBLE_VALID; 3157993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 3167993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Check for lowest version from a valid header. */ 3177993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (key_block_valid && lowest_version > combined_version) 3187993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler lowest_version = combined_version; 3197993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler else { 3207993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Key block valid: %d\n", key_block_valid)); 3217993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Combined version: %u\n", 3227993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler (unsigned) combined_version)); 3237993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 3247993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 3257993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 3267993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * If we already have a good kernel, no need to read another 3277993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * one; we only needed to look at the versions to check for 3287993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * rollback. So skip to the next kernel preamble. 3297993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 3304184e626336fa8d794a21208387226f154d77d0fRandall Spangler if (-1 != good_partition) { 3314184e626336fa8d794a21208387226f154d77d0fRandall Spangler VbExStreamClose(stream); 3324184e626336fa8d794a21208387226f154d77d0fRandall Spangler stream = NULL; 3337993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler continue; 3344184e626336fa8d794a21208387226f154d77d0fRandall Spangler } 3357993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 3367993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler body_offset = key_block->key_block_size + 3377993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler preamble->preamble_size; 3384184e626336fa8d794a21208387226f154d77d0fRandall Spangler 3394184e626336fa8d794a21208387226f154d77d0fRandall Spangler /* 3404184e626336fa8d794a21208387226f154d77d0fRandall Spangler * Make sure the kernel starts at or before what we already 3414184e626336fa8d794a21208387226f154d77d0fRandall Spangler * read into kbuf. 3424184e626336fa8d794a21208387226f154d77d0fRandall Spangler * 3434184e626336fa8d794a21208387226f154d77d0fRandall Spangler * We could deal with a larger offset by reading and discarding 3444184e626336fa8d794a21208387226f154d77d0fRandall Spangler * the data in between the vblock and the kernel data. 3454184e626336fa8d794a21208387226f154d77d0fRandall Spangler */ 3464184e626336fa8d794a21208387226f154d77d0fRandall Spangler if (body_offset > KBUF_SIZE) { 3477993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = VBSD_LKP_CHECK_BODY_OFFSET; 3484184e626336fa8d794a21208387226f154d77d0fRandall Spangler VBDEBUG(("Kernel body offset is %d > 64KB.\n", 3494184e626336fa8d794a21208387226f154d77d0fRandall Spangler (int)body_offset)); 3507993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_kernel; 3517993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 3527993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 3537993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (!params->kernel_buffer) { 3547993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Get kernel load address and size from the header. */ 3557993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler params->kernel_buffer = 3567993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler (void *)((long)preamble->body_load_address); 3574184e626336fa8d794a21208387226f154d77d0fRandall Spangler params->kernel_buffer_size = 3584184e626336fa8d794a21208387226f154d77d0fRandall Spangler preamble->body_signature.data_size; 3594184e626336fa8d794a21208387226f154d77d0fRandall Spangler } else if (preamble->body_signature.data_size > 3604184e626336fa8d794a21208387226f154d77d0fRandall Spangler params->kernel_buffer_size) { 3614184e626336fa8d794a21208387226f154d77d0fRandall Spangler VBDEBUG(("Kernel body doesn't fit in memory.\n")); 3624184e626336fa8d794a21208387226f154d77d0fRandall Spangler shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_MEM; 3634184e626336fa8d794a21208387226f154d77d0fRandall Spangler goto bad_kernel; 3647993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 3657993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 3664184e626336fa8d794a21208387226f154d77d0fRandall Spangler /* 3674184e626336fa8d794a21208387226f154d77d0fRandall Spangler * Body signature data size is 64 bit and toread is 32 bit so 3684184e626336fa8d794a21208387226f154d77d0fRandall Spangler * this could technically cause us to read less data. That's 3694184e626336fa8d794a21208387226f154d77d0fRandall Spangler * fine, because a 4 GB kernel is implausible, and if we did 3704184e626336fa8d794a21208387226f154d77d0fRandall Spangler * have one that big, we'd simply read too little data and fail 3714184e626336fa8d794a21208387226f154d77d0fRandall Spangler * to verify it. 3724184e626336fa8d794a21208387226f154d77d0fRandall Spangler */ 3734184e626336fa8d794a21208387226f154d77d0fRandall Spangler body_toread = preamble->body_signature.data_size; 3744184e626336fa8d794a21208387226f154d77d0fRandall Spangler body_readptr = params->kernel_buffer; 3754184e626336fa8d794a21208387226f154d77d0fRandall Spangler 3764184e626336fa8d794a21208387226f154d77d0fRandall Spangler /* 3774184e626336fa8d794a21208387226f154d77d0fRandall Spangler * If we've already read part of the kernel, copy that to the 3784184e626336fa8d794a21208387226f154d77d0fRandall Spangler * beginning of the kernel buffer. 3794184e626336fa8d794a21208387226f154d77d0fRandall Spangler */ 3804184e626336fa8d794a21208387226f154d77d0fRandall Spangler if (body_offset < KBUF_SIZE) { 3814184e626336fa8d794a21208387226f154d77d0fRandall Spangler uint32_t body_copied = KBUF_SIZE - body_offset; 3824184e626336fa8d794a21208387226f154d77d0fRandall Spangler 3834184e626336fa8d794a21208387226f154d77d0fRandall Spangler /* If the kernel is tiny, don't over-copy */ 3844184e626336fa8d794a21208387226f154d77d0fRandall Spangler if (body_copied > body_toread) 3854184e626336fa8d794a21208387226f154d77d0fRandall Spangler body_copied = body_toread; 3864184e626336fa8d794a21208387226f154d77d0fRandall Spangler 3874184e626336fa8d794a21208387226f154d77d0fRandall Spangler Memcpy(body_readptr, kbuf + body_offset, body_copied); 3884184e626336fa8d794a21208387226f154d77d0fRandall Spangler body_toread -= body_copied; 3894184e626336fa8d794a21208387226f154d77d0fRandall Spangler body_readptr += body_copied; 3907993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 3917993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 3927993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Read the kernel data */ 3934184e626336fa8d794a21208387226f154d77d0fRandall Spangler if (body_toread && 3944184e626336fa8d794a21208387226f154d77d0fRandall Spangler 0 != VbExStreamRead(stream, body_toread, body_readptr)) { 3957993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Unable to read kernel data.\n")); 3967993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = VBSD_LKP_CHECK_READ_DATA; 3977993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_kernel; 3987993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 3997993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 4004184e626336fa8d794a21208387226f154d77d0fRandall Spangler /* Close the stream; we're done with it */ 4014184e626336fa8d794a21208387226f154d77d0fRandall Spangler VbExStreamClose(stream); 4024184e626336fa8d794a21208387226f154d77d0fRandall Spangler stream = NULL; 4034184e626336fa8d794a21208387226f154d77d0fRandall Spangler 4047993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Verify kernel data */ 4057993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (0 != VerifyData((const uint8_t *)params->kernel_buffer, 4067993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler params->kernel_buffer_size, 4077993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler &preamble->body_signature, data_key)) { 4087993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Kernel data verification failed.\n")); 4097993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = VBSD_LKP_CHECK_VERIFY_DATA; 4107993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler goto bad_kernel; 4117993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 4127993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 4137993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Done with the kernel signing key, so can free it now */ 4147993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler RSAPublicKeyFree(data_key); 4157993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler data_key = NULL; 416d183644564ec27c106a3eb1931f565fae167a058Randall Spangler 4177993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 4187993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * If we're still here, the kernel is valid. Save the first 4197993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * good partition we find; that's the one we'll boot. 4207993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 4217993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Partition is good.\n")); 4227993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->check_result = VBSD_LKP_CHECK_KERNEL_GOOD; 4237993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (key_block_valid) 4247993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shpart->flags |= VBSD_LKP_FLAG_KEY_BLOCK_VALID; 4257993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 4267993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler good_partition_key_block_valid = key_block_valid; 4277993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 4287993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * TODO: GPT partitions start at 1, but cgptlib starts them at 4297993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * 0. Adjust here, until cgptlib is fixed. 4307993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 4317993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler good_partition = gpt.current_kernel + 1; 4327993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler params->partition_number = gpt.current_kernel + 1; 4337993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler GetCurrentKernelUniqueGuid(&gpt, ¶ms->partition_guid); 4347993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 4357993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * TODO: GetCurrentKernelUniqueGuid() should take a destination 4367993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * size, or the dest should be a struct, so we know it's big 4377993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * enough. 4387993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 4397993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler params->bootloader_address = preamble->bootloader_address; 4407993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler params->bootloader_size = preamble->bootloader_size; 441b7d1f03e368b146d11eab511cd6a573a528bc728Furquan Shaikh if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS) 442b7d1f03e368b146d11eab511cd6a573a528bc728Furquan Shaikh params->flags = preamble->flags; 443741d2b2f8d8f155c4960214fc40097eb143b6ef0Randall Spangler 4447993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Update GPT to note this is the kernel we're trying */ 4457993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_TRY); 4467993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 4477993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 4487993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * If we're in recovery mode or we're about to boot a 4497993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * dev-signed kernel, there's no rollback protection, so we can 4507993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * stop at the first valid kernel. 4517993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 4527993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (kBootRecovery == boot_mode || !key_block_valid) { 4537993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("In recovery mode or dev-signed kernel\n")); 4547993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler break; 4557993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 4567993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 4577993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 4587993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * Otherwise, we do care about the key index in the TPM. If 4597993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * the good partition's key version is the same as the tpm, 4607993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * then the TPM doesn't need updating; we can stop now. 4617993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * Otherwise, we'll check all the other headers to see if they 4627993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * contain a newer key. 4637993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 4647993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (combined_version == shared->kernel_version_tpm) { 4657993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Same kernel version\n")); 4667993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler break; 4677993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 4687993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 4697993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Continue, so that we skip the error handling code below */ 4707993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler continue; 4717993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 4727993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler bad_kernel: 4737993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Handle errors parsing this kernel */ 4744184e626336fa8d794a21208387226f154d77d0fRandall Spangler if (NULL != stream) 4754184e626336fa8d794a21208387226f154d77d0fRandall Spangler VbExStreamClose(stream); 4767993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (NULL != data_key) 4777993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler RSAPublicKeyFree(data_key); 4787993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 4797993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Marking kernel as invalid.\n")); 4807993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD); 4817993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 4827993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 4837993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } /* while(GptNextKernelEntry) */ 4847993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 4857993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler bad_gpt: 4867993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 4877993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Free kernel buffer */ 4887993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (kbuf) 4897993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VbExFree(kbuf); 4907993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 4917993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Write and free GPT data */ 4927993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler WriteAndFreeGptData(params->disk_handle, &gpt); 4937993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 4947993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Handle finding a good partition */ 4957993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (good_partition >= 0) { 4967993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VBDEBUG(("Good_partition >= 0\n")); 4977993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shcall->check_result = VBSD_LKC_CHECK_GOOD_PARTITION; 4987993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shared->kernel_version_lowest = lowest_version; 4997993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 5007993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * Sanity check - only store a new TPM version if we found one. 5017993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * If lowest_version is still at its initial value, we didn't 5027993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * find one; for example, we're in developer mode and just 5037993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * didn't look. 5047993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 5057993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (lowest_version != LOWEST_TPM_VERSION && 5067993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler lowest_version > shared->kernel_version_tpm) 5077993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shared->kernel_version_tpm = lowest_version; 5087993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 5097993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Success! */ 5107993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler retval = VBERROR_SUCCESS; 5117993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } else if (found_partitions > 0) { 5127993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shcall->check_result = VBSD_LKC_CHECK_INVALID_PARTITIONS; 5137993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler recovery = VBNV_RECOVERY_RW_INVALID_OS; 5147993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler retval = VBERROR_INVALID_KERNEL_FOUND; 5157993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } else { 5167993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shcall->check_result = VBSD_LKC_CHECK_NO_PARTITIONS; 5177993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler recovery = VBNV_RECOVERY_RW_NO_OS; 5187993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler retval = VBERROR_NO_KERNEL_FOUND; 5197993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler } 5207993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 5217993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler LoadKernelExit: 5227993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 5237993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Store recovery request, if any */ 5247993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler VbNvSet(vnc, VBNV_RECOVERY_REQUEST, VBERROR_SUCCESS != retval ? 5257993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler recovery : VBNV_RECOVERY_NOT_REQUESTED); 5267993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 5277993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* 5287993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * If LoadKernel() was called with bad parameters, shcall may not be 5297993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler * initialized. 5307993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler */ 5317993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (shcall) 5327993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shcall->return_code = (uint8_t)retval; 5337993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 5347993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Save whether the good partition's key block was fully verified */ 5357993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler if (good_partition_key_block_valid) 5367993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler shared->flags |= VBSD_KERNEL_KEY_VERIFIED; 5377993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 5387993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler /* Store how much shared data we used, if any */ 5397993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler params->shared_data_size = shared->data_used; 5407993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler 541527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass if (free_kernel_subkey) 542527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass VbExFree(kernel_subkey); 543527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass 5447993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler return retval; 545d183644564ec27c106a3eb1931f565fae167a058Randall Spangler} 546