This is necessary to pass additional information about whether firmware A or B is being run. This change also passes the GBB directly into LoadFirmware() and LoadKernel().

Change-Id: I976c11c82c3d665a4feb88226e919f16c2440f60

BUG=chrome-os-partner:1657
TEST=manual - see below

make && make runtests

Then test verifying a test image in both dev mode (-b1, no key specified) and recovery mode (key specified)

build/utility/load_kernel_test -b1 ~/b/USB_images/0.11.224.0-alex/chromiumos_test_image.bin

build/utility/load_kernel_test ~/b/USB_images/0.11.224.0-alex/chromiumos_test_image.bin tests/devkeys/recovery_key.vbpubk

And make sure the firmware with this change actually boots to USB and SSD.

NOTE: u-boot-next needs to change to work with this change.  will attempt a follow-up CL with that change

Review URL: http://codereview.chromium.org/6626045
This commit is contained in:
Randall Spangler
2011-03-09 15:54:16 -08:00
parent c324fbfb6d
commit 95c4031ce9
12 changed files with 278 additions and 71 deletions

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2010-2011 The Chromium OS Authors. All rights reserved. /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -12,10 +12,8 @@
#include "sysincludes.h" #include "sysincludes.h"
#include "vboot_nvstorage.h" #include "vboot_nvstorage.h"
/* Recommended size of kernel_sign_key_blob in bytes, for /* Recommended size of shared_data_blob in bytes. */
* implementations which must preallocate a transfer buffer between #define LOAD_FIRMWARE_SHARED_DATA_REC_SIZE 16384
* boot phases */
#define LOAD_FIRMWARE_KEY_BLOB_REC_SIZE 2104
/* Return codes for LoadFirmware() and S3Resume(). */ /* Return codes for LoadFirmware() and S3Resume(). */
#define LOAD_FIRMWARE_SUCCESS 0 /* Success */ #define LOAD_FIRMWARE_SUCCESS 0 /* Success */
@@ -29,19 +27,21 @@
typedef struct LoadFirmwareParams { typedef struct LoadFirmwareParams {
/* Inputs to LoadFirmware() */ /* Inputs to LoadFirmware() */
void *firmware_root_key_blob; /* Key used to sign firmware header */ void* gbb_data; /* Pointer to GBB data */
void *verification_block_0; /* Key block + preamble for firmware 0 */ uint64_t gbb_size; /* Size of GBB data in bytes */
void *verification_block_1; /* Key block + preamble for firmware 1 */ void* verification_block_0; /* Key block + preamble for firmware 0 */
void* verification_block_1; /* Key block + preamble for firmware 1 */
uint64_t verification_size_0; /* Verification block 0 size in bytes */ uint64_t verification_size_0; /* Verification block 0 size in bytes */
uint64_t verification_size_1; /* Verification block 1 size in bytes */ uint64_t verification_size_1; /* Verification block 1 size in bytes */
void *kernel_sign_key_blob; /* Destination buffer for key to use void* shared_data_blob; /* Destination buffer for data shared between
* when loading kernel. Pass this * LoadFirmware() and LoadKernel(). Pass this
* data to LoadKernel() in * data to LoadKernel() in
* LoadKernelParams.header_sign_key_blob. */ * LoadKernelParams.shared_data_blob. */
uint64_t kernel_sign_key_size; /* Size of kernel signing key blob uint64_t shared_data_size; /* Size of shared data blob buffer, in bytes.
* buffer, in bytes. On output, this * On output, this will contain the actual
* will contain the actual key blob * data size placed into the buffer. Caller
* size placed into the buffer. */ * need only pass this much data to
* LoadKernel().*/
uint64_t boot_flags; /* Boot flags */ uint64_t boot_flags; /* Boot flags */
VbNvContext* nv_context; /* Context for NV storage. nv_context->raw VbNvContext* nv_context; /* Context for NV storage. nv_context->raw
* must be filled before calling * must be filled before calling

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2010-2011 The Chromium OS Authors. All rights reserved. /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -34,7 +34,15 @@
typedef struct LoadKernelParams { typedef struct LoadKernelParams {
/* Inputs to LoadKernel() */ /* Inputs to LoadKernel() */
void* header_sign_key_blob; /* Key blob used to sign the kernel header */ void* shared_data_blob; /* Buffer for data shared between
* LoadFirmware() and LoadKernel(). Pass the
* same buffer which was passed to
* LoadFirmware(). */
uint64_t shared_data_size; /* Size of shared data blob buffer, in bytes.
* On output, this will contain the actual
* data size placed into the buffer. */
void* gbb_data; /* Pointer to GBB data */
uint64_t gbb_size; /* Size of GBB data in bytes */
uint64_t bytes_per_lba; /* Bytes per lba sector on current device */ uint64_t bytes_per_lba; /* Bytes per lba sector on current device */
uint64_t ending_lba; /* Last addressable lba sector on current uint64_t ending_lba; /* Last addressable lba sector on current
* device */ * device */

View File

@@ -74,6 +74,8 @@ typedef enum VbNvParam {
#define VBNV_RECOVERY_RO_S3_RESUME 0x04 #define VBNV_RECOVERY_RO_S3_RESUME 0x04
/* TPM error in read-only firmware */ /* TPM error in read-only firmware */
#define VBNV_RECOVERY_RO_TPM_ERROR 0x05 #define VBNV_RECOVERY_RO_TPM_ERROR 0x05
/* Shared data error in read-only firmware */
#define VBNV_RECOVERY_RO_SHARED_DATA 0x06
/* Unspecified/unknown error in read-only firmware */ /* Unspecified/unknown error in read-only firmware */
#define VBNV_RECOVERY_RO_UNSPECIFIED 0x3F #define VBNV_RECOVERY_RO_UNSPECIFIED 0x3F
/* User manually requested recovery by pressing a key at developer /* User manually requested recovery by pressing a key at developer
@@ -87,6 +89,8 @@ typedef enum VbNvParam {
#define VBNV_RECOVERY_RW_TPM_ERROR 0x44 #define VBNV_RECOVERY_RW_TPM_ERROR 0x44
/* RW firmware in dev mode, but dev switch is off */ /* RW firmware in dev mode, but dev switch is off */
#define VBNV_RECOVERY_RW_DEV_MISMATCH 0x45 #define VBNV_RECOVERY_RW_DEV_MISMATCH 0x45
/* Shared data error in rewritable firmware */
#define VBNV_RECOVERY_RW_SHARED_DATA 0x46
/* Unspecified/unknown error in rewritable firmware */ /* Unspecified/unknown error in rewritable firmware */
#define VBNV_RECOVERY_RW_UNSPECIFIED 0x7F #define VBNV_RECOVERY_RW_UNSPECIFIED 0x7F
/* DM-verity error */ /* DM-verity error */

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2010-2011 The Chromium OS Authors. All rights reserved. /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -131,6 +131,49 @@ typedef struct VbKernelPreambleHeader {
#define EXPECTED_VBKERNELPREAMBLEHEADER_SIZE 96 #define EXPECTED_VBKERNELPREAMBLEHEADER_SIZE 96
/* Minimum and recommended size of shared_data_blob in bytes. */
#define VB_SHARED_DATA_MIN_SIZE 3072
#define VB_SHARED_DATA_REC_SIZE 16384
/* Data shared between LoadFirmware(), LoadKernel(), and OS.
*
* The boot process is:
* 1) Caller allocates buffer, at least VB_SHARED_DATA_MIN bytes, ideally
* VB_SHARED_DATA_REC_SIZE bytes.
* 2) If non-recovery boot, this is passed to LoadFirmware(), which
* initializes the buffer, adding this header and some data.
* 3) Buffer is passed to LoadKernel(). If this is a recovery boot,
* LoadKernel() initializes the buffer, adding this header. Regardless
* of boot type, LoadKernel() adds some data to the buffer.
* 4) Caller makes data available to the OS in a platform-dependent manner.
* For example, via ACPI or ATAGs. */
typedef struct VbSharedDataHeader {
/* Fields present in version 1 */
uint32_t struct_version; /* Version of this structure */
uint64_t struct_size; /* Size of this structure in bytes */
uint64_t data_size; /* Size of shared data buffer in bytes */
uint64_t data_used; /* Amount of shared data used so far */
VbPublicKey kernel_subkey; /* Kernel subkey, from firmware */
uint64_t kernel_subkey_data_offset; /* Offset of kernel subkey data from
* start of this struct */
uint64_t kernel_subkey_data_size; /* Offset of kernel subkey data */
uint64_t flags; /* Flags */
/* After read-only firmware which uses version 1 is released, any additional
* fields must be added below, and the struct version must be increased.
* Before reading/writing those fields, make sure that the struct being
* accessed is at least version 2.
*
* It's always ok for an older firmware to access a newer struct, since all
* the fields it knows about are present. Newer firmware needs to use
* reasonable defaults when accessing older structs. */
} __attribute__((packed)) VbSharedDataHeader;
#define VB_SHARED_DATA_VERSION 1 /* Version for struct_version */
__pragma(pack(pop)) /* Support packing for MSVC. */ __pragma(pack(pop)) /* Support packing for MSVC. */
#endif /* VBOOT_REFERENCE_VBOOT_STRUCT_H_ */ #endif /* VBOOT_REFERENCE_VBOOT_STRUCT_H_ */

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -23,6 +23,7 @@ enum {
VBOOT_PREAMBLE_INVALID, /* Preamble internal structure is VBOOT_PREAMBLE_INVALID, /* Preamble internal structure is
* invalid */ * invalid */
VBOOT_PREAMBLE_SIGNATURE, /* Preamble signature check failed */ VBOOT_PREAMBLE_SIGNATURE, /* Preamble signature check failed */
VBOOT_SHARED_DATA_INVALID, /* Shared data is invalid. */
VBOOT_ERROR_MAX, VBOOT_ERROR_MAX,
}; };
extern char* kVbootErrors[VBOOT_ERROR_MAX]; extern char* kVbootErrors[VBOOT_ERROR_MAX];
@@ -107,6 +108,20 @@ int VerifyKernelPreamble(const VbKernelPreambleHeader* preamble,
uint64_t size, const RSAPublicKey* key); uint64_t size, const RSAPublicKey* key);
/* Initialize a verified boot shared data structure.
*
* Returns 0 if success, non-zero if error. */
int VbSharedDataInit(VbSharedDataHeader* header, uint64_t size);
/* Reserve [size] bytes of the shared data area. Returns the offset of the
* reserved data from the start of the shared data buffer, or 0 if error. */
uint64_t VbSharedDataReserve(VbSharedDataHeader* header, uint64_t size);
/* Copy the kernel subkey into the shared data.
*
* Returns 0 if success, non-zero if error. */
int VbSharedDataSetKernelKey(VbSharedDataHeader* header,
const VbPublicKey* src);
#endif /* VBOOT_REFERENCE_VBOOT_COMMON_H_ */ #endif /* VBOOT_REFERENCE_VBOOT_COMMON_H_ */

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -19,6 +19,7 @@ char* kVbootErrors[VBOOT_ERROR_MAX] = {
"Public key invalid.", "Public key invalid.",
"Preamble invalid.", "Preamble invalid.",
"Preamble signature check failed.", "Preamble signature check failed.",
"Shared data invalid."
}; };
@@ -377,3 +378,67 @@ int VerifyKernelPreamble(const VbKernelPreambleHeader* preamble,
/* Success */ /* Success */
return VBOOT_SUCCESS; return VBOOT_SUCCESS;
} }
int VbSharedDataInit(VbSharedDataHeader* header, uint64_t size) {
if (size < sizeof(VbSharedDataHeader)) {
VBDEBUG(("Not enough data for header.\n"));
return VBOOT_SHARED_DATA_INVALID;
}
if (size < VB_SHARED_DATA_MIN_SIZE) {
VBDEBUG(("Shared data buffer too small.\n"));
return VBOOT_SHARED_DATA_INVALID;
}
if (!header)
return VBOOT_SHARED_DATA_INVALID;
/* Zero the header */
Memset(header, 0, sizeof(VbSharedDataHeader));
/* Initialize fields */
header->struct_version = VB_SHARED_DATA_VERSION;
header->struct_size = sizeof(VbSharedDataHeader);
header->data_size = size;
header->data_used = sizeof(VbSharedDataHeader);
/* Success */
return VBOOT_SUCCESS;
}
uint64_t VbSharedDataReserve(VbSharedDataHeader* header, uint64_t size) {
uint64_t offs = header->data_used;
if (!header || size > header->data_size - header->data_used) {
VBDEBUG(("VbSharedData buffer out of space.\n"));
return 0; /* Not initialized, or not enough space left. */
}
header->data_used += size;
return offs;
}
int VbSharedDataSetKernelKey(VbSharedDataHeader* header,
const VbPublicKey* src) {
VbPublicKey *kdest = &header->kernel_subkey;
if (!header)
return VBOOT_SHARED_DATA_INVALID;
/* Attempt to allocate space for the key, if it hasn't been allocated yet */
if (!header->kernel_subkey_data_offset) {
header->kernel_subkey_data_offset = VbSharedDataReserve(header,
src->key_size);
if (!header->kernel_subkey_data_offset)
return VBOOT_SHARED_DATA_INVALID;
header->kernel_subkey_data_size = src->key_size;
}
/* Copy the kernel sign key blob into the destination buffer */
PublicKeyInit(kdest, (uint8_t*)header + header->kernel_subkey_data_offset,
header->kernel_subkey_data_size);
return PublicKeyCopy(kdest, src);
}

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2010-2011 The Chromium OS Authors. All rights reserved. /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -6,6 +6,7 @@
* (Firmware portion) * (Firmware portion)
*/ */
#include "gbb_header.h"
#include "load_firmware_fw.h" #include "load_firmware_fw.h"
#include "rollback_index.h" #include "rollback_index.h"
#include "utility.h" #include "utility.h"
@@ -39,8 +40,9 @@ int LoadFirmwareSetup(void) {
int LoadFirmware(LoadFirmwareParams* params) { int LoadFirmware(LoadFirmwareParams* params) {
VbSharedDataHeader* shared = (VbSharedDataHeader*)params->shared_data_blob;
VbPublicKey* root_key = (VbPublicKey*)params->firmware_root_key_blob; GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)params->gbb_data;
VbPublicKey* root_key;
VbLoadFirmwareInternal* lfi; VbLoadFirmwareInternal* lfi;
VbNvContext* vnc = params->nv_context; VbNvContext* vnc = params->nv_context;
@@ -64,16 +66,19 @@ int LoadFirmware(LoadFirmwareParams* params) {
/* Setup NV storage */ /* Setup NV storage */
VbNvSetup(vnc); VbNvSetup(vnc);
if (params->kernel_sign_key_size < sizeof(VbPublicKey)) { /* Initialize shared data structure. */
VBDEBUG(("Kernel sign key buffer too small\n")); if (0 != VbSharedDataInit(shared, params->shared_data_size)) {
VBDEBUG(("Shared data init error\n"));
recovery = VBNV_RECOVERY_RO_SHARED_DATA;
goto LoadFirmwareExit; goto LoadFirmwareExit;
} }
/* Must have a root key */ /* Must have a root key from the GBB */
if (!root_key) { if (!gbb) {
VBDEBUG(("No root key\n")); VBDEBUG(("No GBB\n"));
goto LoadFirmwareExit; goto LoadFirmwareExit;
} }
root_key = (VbPublicKey*)((uint8_t*)gbb + gbb->rootkey_offset);
/* Parse flags */ /* Parse flags */
is_dev = (params->boot_flags & BOOT_FLAG_DEVELOPER ? 1 : 0); is_dev = (params->boot_flags & BOOT_FLAG_DEVELOPER ? 1 : 0);
@@ -235,21 +240,13 @@ int LoadFirmware(LoadFirmwareParams* params) {
/* If we're still here, the firmware is valid. */ /* If we're still here, the firmware is valid. */
VBDEBUG(("Firmware %d is valid.\n", index)); VBDEBUG(("Firmware %d is valid.\n", index));
if (-1 == good_index) { if (-1 == good_index) {
VbPublicKey *kdest = (VbPublicKey*)params->kernel_sign_key_blob; /* Save the key we actually used */
if (0 != VbSharedDataSetKernelKey(shared, &preamble->kernel_subkey)) {
/* Copy the kernel sign key blob into the destination buffer */ VBDEBUG(("Unable to save kernel subkey to shared data.\n"));
PublicKeyInit(kdest, (uint8_t*)(kdest + 1),
(params->kernel_sign_key_size - sizeof(VbPublicKey)));
if (0 != PublicKeyCopy(kdest, &preamble->kernel_subkey)) {
VBDEBUG(("Kernel subkey too big for buffer.\n"));
continue; /* The firmware signature was good, but the public continue; /* The firmware signature was good, but the public
* key was bigger that the caller can handle. */ * key was bigger that the caller can handle. */
} }
/* Save the key size we actually used */
params->kernel_sign_key_size = kdest->key_offset + kdest->key_size;
/* Save the good index, now that we're sure we can actually use /* Save the good index, now that we're sure we can actually use
* this firmware. That's the one we'll boot. */ * this firmware. That's the one we'll boot. */
good_index = index; good_index = index;
@@ -314,6 +311,10 @@ LoadFirmwareExit:
recovery : VBNV_RECOVERY_NOT_REQUESTED); recovery : VBNV_RECOVERY_NOT_REQUESTED);
VbNvTeardown(vnc); VbNvTeardown(vnc);
/* Note that we don't reduce params->shared_data_size to shared->data_used,
* since we want to leave space for LoadKernel() to add to the shared data
* buffer. */
return retval; return retval;
} }

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2010-2011 The Chromium OS Authors. All rights reserved. /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -11,6 +11,7 @@
#include "boot_device.h" #include "boot_device.h"
#include "cgptlib.h" #include "cgptlib.h"
#include "cgptlib_internal.h" #include "cgptlib_internal.h"
#include "gbb_header.h"
#include "load_kernel_fw.h" #include "load_kernel_fw.h"
#include "rollback_index.h" #include "rollback_index.h"
#include "utility.h" #include "utility.h"
@@ -118,7 +119,9 @@ int WriteAndFreeGptData(GptData* gptdata) {
__pragma(warning(disable: 4127)) __pragma(warning(disable: 4127))
int LoadKernel(LoadKernelParams* params) { int LoadKernel(LoadKernelParams* params) {
VbSharedDataHeader* shared = (VbSharedDataHeader*)params->shared_data_blob;
VbNvContext* vnc = params->nv_context; VbNvContext* vnc = params->nv_context;
GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)params->gbb_data;
VbPublicKey* kernel_subkey; VbPublicKey* kernel_subkey;
GptData gpt; GptData gpt;
uint64_t part_start, part_size; uint64_t part_start, part_size;
@@ -154,7 +157,6 @@ int LoadKernel(LoadKernelParams* params) {
} }
/* Initialization */ /* Initialization */
kernel_subkey = (VbPublicKey*)params->header_sign_key_blob;
blba = params->bytes_per_lba; blba = params->bytes_per_lba;
kbuf_sectors = KBUF_SIZE / blba; kbuf_sectors = KBUF_SIZE / blba;
if (0 == kbuf_sectors) { if (0 == kbuf_sectors) {
@@ -187,14 +189,30 @@ int LoadKernel(LoadKernelParams* params) {
params->bootloader_address = 0; params->bootloader_address = 0;
params->bootloader_size = 0; params->bootloader_size = 0;
/* Let the TPM know if we're in recovery mode */
if (kBootRecovery == boot_mode) { if (kBootRecovery == boot_mode) {
/* Initialize the shared data structure, since LoadFirmware() didn't do it
* for us. */
if (0 != VbSharedDataInit(shared, params->shared_data_size)) {
/* Error initializing the shared data, but we can keep going. We just
* can't use the shared data. */
VBDEBUG(("Shared data init error\n"));
params->shared_data_size = 0;
shared = NULL;
}
/* Use the recovery key to verify the kernel */
kernel_subkey = (VbPublicKey*)((uint8_t*)gbb + gbb->recovery_key_offset);
/* Let the TPM know if we're in recovery mode */
if (0 != RollbackKernelRecovery(dev_switch)) { if (0 != RollbackKernelRecovery(dev_switch)) {
VBDEBUG(("Error setting up TPM for recovery kernel\n")); VBDEBUG(("Error setting up TPM for recovery kernel\n"));
/* Ignore return code, since we need to boot recovery mode to /* Ignore return code, since we need to boot recovery mode to
* fix the TPM. */ * fix the TPM. */
} }
} else { } else {
/* Use the kernel subkey passed from LoadFirmware(). */
kernel_subkey = &shared->kernel_subkey;
/* Read current kernel key index from TPM. Assumes TPM is already /* Read current kernel key index from TPM. Assumes TPM is already
* initialized. */ * initialized. */
status = RollbackKernelRead(&tpm_version); status = RollbackKernelRead(&tpm_version);
@@ -505,5 +523,9 @@ LoadKernelExit:
recovery : VBNV_RECOVERY_NOT_REQUESTED); recovery : VBNV_RECOVERY_NOT_REQUESTED);
VbNvTeardown(vnc); VbNvTeardown(vnc);
/* Store how much shared data we used, if any */
if (shared)
params->shared_data_size = shared->data_used;
return retval; return retval;
} }

View File

@@ -79,6 +79,9 @@ int main(void)
KeyBlockVerify(0, 0, 0, 0); KeyBlockVerify(0, 0, 0, 0);
VerifyFirmwarePreamble(0, 0, 0); VerifyFirmwarePreamble(0, 0, 0);
VerifyKernelPreamble(0, 0, 0); VerifyKernelPreamble(0, 0, 0);
VbSharedDataInit(0, 0);
VbSharedDataReserve(0, 0);
VbSharedDataSetKernelKey(0, 0);
VbNvSetup(0); VbNvSetup(0);
VbNvGet(0, 0, 0); VbNvGet(0, 0, 0);

View File

@@ -63,7 +63,8 @@ int GetFirmwareBody(LoadFirmwareParams* params, uint64_t index) {
* volumes, this call will still be slow. Once we reach feature * volumes, this call will still be slow. Once we reach feature
* complete, you should modify your code to call LoadImage() * complete, you should modify your code to call LoadImage()
* directly. */ * directly. */
int VerifyFirmwareDriver_stub(uint8_t* root_key_blob, int VerifyFirmwareDriver_stub(uint8_t* gbb_data,
uint64_t gbb_size,
uint8_t* verification_headerA, uint8_t* verification_headerA,
uint8_t* firmwareA, uint8_t* firmwareA,
uint8_t* verification_headerB, uint8_t* verification_headerB,
@@ -91,14 +92,15 @@ int VerifyFirmwareDriver_stub(uint8_t* root_key_blob,
/* Set up the params for LoadFirmware() */ /* Set up the params for LoadFirmware() */
p.caller_internal = &ci; p.caller_internal = &ci;
p.firmware_root_key_blob = root_key_blob; p.gbb_data = gbb_data;
p.gbb_size = gbb_size;
p.verification_block_0 = verification_headerA; p.verification_block_0 = verification_headerA;
p.verification_block_1 = verification_headerB; p.verification_block_1 = verification_headerB;
p.nv_context = &vnc; p.nv_context = &vnc;
/* Allocate a key blob buffer */ /* Allocate a shared data buffer */
p.kernel_sign_key_blob = Malloc(LOAD_FIRMWARE_KEY_BLOB_REC_SIZE); p.shared_data_blob = Malloc(LOAD_FIRMWARE_SHARED_DATA_REC_SIZE);
p.kernel_sign_key_size = LOAD_FIRMWARE_KEY_BLOB_REC_SIZE; p.shared_data_size = LOAD_FIRMWARE_SHARED_DATA_REC_SIZE;
/* TODO: YOU NEED TO SET THE BOOT FLAGS SOMEHOW */ /* TODO: YOU NEED TO SET THE BOOT FLAGS SOMEHOW */
p.boot_flags = 0; p.boot_flags = 0;
@@ -111,8 +113,8 @@ int VerifyFirmwareDriver_stub(uint8_t* root_key_blob,
} }
if (LOAD_FIRMWARE_SUCCESS == rv) { if (LOAD_FIRMWARE_SUCCESS == rv) {
/* TODO: YOU NEED TO KEEP TRACK OF p.kernel_sign_key_blob AND /* TODO: YOU NEED TO KEEP TRACK OF p.shared_data_blob AND
* p.kernel_sign_key_size SO YOU CAN PASS THEM TO LoadKernel(). */ * p.shared_data_size SO YOU CAN PASS THEM TO LoadKernel(). */
return (0 == p.firmware_index ? BOOT_FIRMWARE_A_CONTINUE : return (0 == p.firmware_index ? BOOT_FIRMWARE_A_CONTINUE :
BOOT_FIRMWARE_B_CONTINUE); BOOT_FIRMWARE_B_CONTINUE);

View File

@@ -44,27 +44,26 @@ int GetFirmwareBody(LoadFirmwareParams* params, uint64_t firmware_index) {
return 0; return 0;
} }
/* Get firmware root key /* Get GBB
* *
* Return pointer to firmware root key of firmware image, or NULL if not found * Return pointer to GBB from firmware image, or NULL if not found.
* *
* [base_of_rom] pointer to firmware image * [base_of_rom] pointer to firmware image
* [fmap] pointer to Flash Map of firmware image * [fmap] pointer to Flash Map of firmware image
* [gbb_size] GBB size will be stored here if GBB is found
*/ */
void* GetFirmwareRootKey(const void* base_of_rom, const void* fmap) { void* GetFirmwareGBB(const void* base_of_rom, const void* fmap,
uint64_t* gbb_size) {
const FmapHeader* fh = (const FmapHeader*) fmap; const FmapHeader* fh = (const FmapHeader*) fmap;
const FmapAreaHeader* ah = (const FmapAreaHeader*) const FmapAreaHeader* ah = (const FmapAreaHeader*)
(fmap + sizeof(FmapHeader)); (fmap + sizeof(FmapHeader));
int i = FmapAreaIndexOrError(fh, ah, "GBB Area"); int i = FmapAreaIndexOrError(fh, ah, "GBB Area");
const void* gbb;
const GoogleBinaryBlockHeader* gbbh;
if (i < 0) if (i < 0)
return NULL; return NULL;
gbb = base_of_rom + ah[i].area_offset; *gbb_size = ah[i].area_size;
gbbh = (const GoogleBinaryBlockHeader*) gbb; return (void*)(base_of_rom + ah[i].area_offset);
return (void*) gbb + gbbh->rootkey_offset;
} }
/* Get verification block /* Get verification block
@@ -151,15 +150,14 @@ int DriveLoadFirmware(const void* base_of_rom, const void* fmap) {
/* Initialize LoadFirmwareParams lfp */ /* Initialize LoadFirmwareParams lfp */
lfp.caller_internal = &ci; lfp.caller_internal = &ci;
lfp.gbb_data = GetFirmwareGBB(base_of_rom, fmap, &lfp.gbb_size);
lfp.firmware_root_key_blob = GetFirmwareRootKey(base_of_rom, fmap); if (!lfp.gbb_data) {
if (!lfp.firmware_root_key_blob) { printf("ERROR: cannot get firmware GBB\n");
printf("ERROR: cannot get firmware root key blob\n");
return 1; return 1;
} }
printf("firmware root key blob at 0x%08" PRIx64 "\n", printf("firmware GBB at 0x%08" PRIx64 "\n",
(uint64_t) (lfp.firmware_root_key_blob - base_of_rom)); (uint64_t) (lfp.gbb_data - base_of_rom));
/* Loop to initialize firmware key and data A / B */ /* Loop to initialize firmware key and data A / B */
for (index = 0; index < 2; ++index) { for (index = 0; index < 2; ++index) {
@@ -186,9 +184,9 @@ int DriveLoadFirmware(const void* base_of_rom, const void* fmap) {
ci.firmware[index].size); ci.firmware[index].size);
} }
lfp.kernel_sign_key_blob = Malloc(LOAD_FIRMWARE_KEY_BLOB_REC_SIZE); lfp.shared_data_blob = Malloc(VB_SHARED_DATA_MIN_SIZE);
lfp.kernel_sign_key_size = LOAD_FIRMWARE_KEY_BLOB_REC_SIZE; lfp.shared_data_size = VB_SHARED_DATA_MIN_SIZE;
printf("kernel sign key size is 0x%08" PRIx64 "\n", lfp.kernel_sign_key_size); printf("shared data size 0x%08" PRIx64 "\n", lfp.shared_data_size);
lfp.boot_flags = 0; lfp.boot_flags = 0;
printf("boot flags is 0x%08" PRIx64 "\n", lfp.boot_flags); printf("boot flags is 0x%08" PRIx64 "\n", lfp.boot_flags);
@@ -202,7 +200,7 @@ int DriveLoadFirmware(const void* base_of_rom, const void* fmap) {
if (status == LOAD_FIRMWARE_SUCCESS) if (status == LOAD_FIRMWARE_SUCCESS)
printf("firmwiare index is %" PRIu64 "\n", lfp.firmware_index); printf("firmwiare index is %" PRIu64 "\n", lfp.firmware_index);
Free(lfp.kernel_sign_key_blob); Free(lfp.shared_data_blob);
return 0; return 0;
} }

View File

@@ -14,11 +14,14 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "load_firmware_fw.h"
#include "load_kernel_fw.h" #include "load_kernel_fw.h"
#include "boot_device.h" #include "boot_device.h"
#include "gbb_header.h"
#include "host_common.h" #include "host_common.h"
#include "rollback_index.h" #include "rollback_index.h"
#include "utility.h" #include "utility.h"
#include "vboot_common.h"
#include "vboot_kernel.h" #include "vboot_kernel.h"
#define LBA_BYTES 512 #define LBA_BYTES 512
@@ -77,6 +80,10 @@ int BootDeviceWriteLBA(uint64_t lba_start, uint64_t lba_count,
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
const char* image_name; const char* image_name;
uint64_t key_size;
uint8_t* key_blob = NULL;
VbSharedDataHeader* shared;
GoogleBinaryBlockHeader* gbb;
int rv, c, argsleft; int rv, c, argsleft;
int errorcnt = 0; int errorcnt = 0;
char *e = 0; char *e = 0;
@@ -136,14 +143,53 @@ int main(int argc, char* argv[]) {
/* Read header signing key blob */ /* Read header signing key blob */
if (argsleft > 1) { if (argsleft > 1) {
uint64_t key_size; key_blob = ReadFile(argv[optind+1], &key_size);
lkp.header_sign_key_blob = ReadFile(argv[optind+1], &key_size); if (!key_blob) {
if (!lkp.header_sign_key_blob) {
fprintf(stderr, "Unable to read key file %s\n", argv[optind+1]); fprintf(stderr, "Unable to read key file %s\n", argv[optind+1]);
return 1; return 1;
} }
printf("Read %" PRIu64 " bytes of key from %s\n", key_size, argv[optind+1]);
} }
/* Need to skip the address check, since we're putting it somewhere on the
/* Initialize the GBB */
lkp.gbb_size = sizeof(GoogleBinaryBlockHeader) + key_size;
lkp.gbb_data = (void*)Malloc(lkp.gbb_size);
gbb = (GoogleBinaryBlockHeader*)lkp.gbb_data;
Memset(gbb, 0, lkp.gbb_size);
Memcpy(gbb->signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE);
gbb->major_version = GBB_MAJOR_VER;
gbb->minor_version = GBB_MINOR_VER;
gbb->header_size = sizeof(GoogleBinaryBlockHeader);
/* Fill in the given key, if any, for both root and recovery */
if (key_blob) {
gbb->rootkey_offset = gbb->header_size;
gbb->rootkey_size = key_size;
Memcpy((uint8_t*)gbb + gbb->rootkey_offset, key_blob, key_size);
gbb->recovery_key_offset = gbb->rootkey_offset;
gbb->recovery_key_size = key_size;
}
/* Initialize the shared data area */
lkp.shared_data_blob = Malloc(LOAD_FIRMWARE_SHARED_DATA_REC_SIZE);
lkp.shared_data_size = LOAD_FIRMWARE_SHARED_DATA_REC_SIZE;
shared = (VbSharedDataHeader*)lkp.shared_data_blob;
if (0 != VbSharedDataInit(shared, lkp.shared_data_size)) {
fprintf(stderr, "Unable to init shared data\n");
return 1;
}
/* Copy in the key blob, if any */
if (key_blob) {
if (0 != VbSharedDataSetKernelKey(shared, (VbPublicKey*)key_blob)) {
fprintf(stderr, "Unable to set key in shared data\n");
return 1;
}
}
/* Free the key blob, now that we're done with it */
Free(key_blob);
/* Needs to skip the address check, since we're putting it somewhere on the
* heap instead of its actual target address in the firmware. */ * heap instead of its actual target address in the firmware. */
lkp.boot_flags |= BOOT_FLAG_SKIP_ADDR_CHECK; lkp.boot_flags |= BOOT_FLAG_SKIP_ADDR_CHECK;