mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-24 02:05:01 +00:00
vboot: Remove vboot1 init and select-firmware APIs
And nuke all the underlying code that is unused once those APIs are gone. These APIs are not used by any project in ToT, having been superseded last year by the vboot2 APIs. No functional changes to live code, just lots of deletes. CQ-DEPEND=CL:347414 BUG=chromium:611535 BRANCH=none TEST=make runtests; build samus Change-Id: I05ac752d74d1343dd03600b1c5e6ed22822e2802 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/347257
This commit is contained in:
committed by
chrome-bot
parent
c61df529d0
commit
2afa87360d
@@ -1,29 +0,0 @@
|
||||
/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* High-level firmware API for loading and verifying rewritable firmware.
|
||||
* (Firmware Portion)
|
||||
*/
|
||||
|
||||
#ifndef VBOOT_REFERENCE_LOAD_FIRMWARE_FW_H_
|
||||
#define VBOOT_REFERENCE_LOAD_FIRMWARE_FW_H_
|
||||
|
||||
#include "vboot_api.h"
|
||||
#include "vboot_nvstorage.h"
|
||||
#include "vboot_struct.h"
|
||||
|
||||
/**
|
||||
* Load the rewritable firmware.
|
||||
*
|
||||
* Pass the common and firmware params from VbSelectFirmware(), and a
|
||||
* VbNvContext. Caller is responsible for calling VbNvSetup() and
|
||||
* VbNvTeardown() on the VbNvContext.
|
||||
*
|
||||
* Returns VBERROR_SUCCESS if successful. If unsuccessful, sets a recovery
|
||||
* reason via VbNvStorage and returns an error code.
|
||||
*/
|
||||
int LoadFirmware(VbCommonParams *cparams, VbSelectFirmwareParams *fparams,
|
||||
VbNvContext *vnc);
|
||||
|
||||
#endif /* VBOOT_REFERENCE_LOAD_FIRMWARE_FW_H_ */
|
||||
@@ -102,37 +102,6 @@ enum fwmp_flags {
|
||||
|
||||
/* All functions return TPM_SUCCESS (zero) if successful, non-zero if error */
|
||||
|
||||
/*
|
||||
* These functions are called from VbInit(). They cannot use global
|
||||
* variables.
|
||||
*/
|
||||
|
||||
uint32_t RollbackS3Resume(void);
|
||||
|
||||
/*
|
||||
* These functions are callable from VbSelectFirmware(). They cannot use
|
||||
* global variables.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This must be called.
|
||||
*/
|
||||
uint32_t RollbackFirmwareSetup(int is_hw_dev,
|
||||
int disable_dev_request,
|
||||
int clear_tpm_owner_request,
|
||||
/* two outputs on success */
|
||||
int *is_virt_dev, uint32_t *tpm_version);
|
||||
|
||||
/**
|
||||
* Write may be called if the versions change.
|
||||
*/
|
||||
uint32_t RollbackFirmwareWrite(uint32_t version);
|
||||
|
||||
/**
|
||||
* Lock must be called.
|
||||
*/
|
||||
uint32_t RollbackFirmwareLock(void);
|
||||
|
||||
/*
|
||||
* These functions are callable from VbSelectAndLoadKernel(). They may use
|
||||
* global variables.
|
||||
@@ -148,16 +117,6 @@ uint32_t RollbackKernelRead(uint32_t *version);
|
||||
*/
|
||||
uint32_t RollbackKernelWrite(uint32_t version);
|
||||
|
||||
/**
|
||||
* Read backup data.
|
||||
*/
|
||||
uint32_t RollbackBackupRead(uint8_t *raw);
|
||||
|
||||
/**
|
||||
* Write backup data.
|
||||
*/
|
||||
uint32_t RollbackBackupWrite(uint8_t *raw);
|
||||
|
||||
/**
|
||||
* Lock must be called. Internally, it's ignored in recovery mode.
|
||||
*/
|
||||
@@ -192,31 +151,6 @@ uint32_t TPMClearAndReenable(void);
|
||||
*/
|
||||
uint32_t SafeWrite(uint32_t index, const void *data, uint32_t length);
|
||||
|
||||
/**
|
||||
* Similarly to SafeWrite(), this ensures we don't fail a DefineSpace because
|
||||
* we hit the TPM write limit. This is even less likely to happen than with
|
||||
* writes because we only define spaces once at initialization, but we'd rather
|
||||
* be paranoid about this.
|
||||
*/
|
||||
uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size);
|
||||
|
||||
/**
|
||||
* Perform one-time initializations.
|
||||
*
|
||||
* Create the NVRAM spaces, and set their initial values as needed. Sets the
|
||||
* nvLocked bit and ensures the physical presence command is enabled and
|
||||
* locked.
|
||||
*/
|
||||
uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware *rsf,
|
||||
RollbackSpaceKernel *rsk);
|
||||
|
||||
/**
|
||||
* Start the TPM and establish the root of trust for the anti-rollback
|
||||
* mechanism.
|
||||
*/
|
||||
uint32_t SetupTPM(int developer_mode, int disable_dev_request,
|
||||
int clear_tpm_owner_request, RollbackSpaceFirmware *rsf);
|
||||
|
||||
/**
|
||||
* Utility function to turn the virtual dev-mode flag on or off. 0=off, 1=on.
|
||||
*/
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Functions for updating the TPM state with the status of boot path.
|
||||
*/
|
||||
|
||||
#ifndef VBOOT_REFERENCE_TPM_BOOTMODE_H_
|
||||
#define VBOOT_REFERENCE_TPM_BOOTMODE_H_
|
||||
|
||||
#include "gbb_header.h"
|
||||
#include "sysincludes.h"
|
||||
|
||||
/**
|
||||
* Update TPM PCR State with the boot path status.
|
||||
*
|
||||
* [developer_mode]: State of the developer switch.
|
||||
* [recovery_mode]: State of the recovery mode.
|
||||
* [fw_keyblock_flags]: Keyblock flags of the to-be-booted
|
||||
* RW firmware keyblock.
|
||||
* [gbb]: Pointer to GBB header from RO firmware.
|
||||
*
|
||||
* Returns: TPM_SUCCESS if the TPM extend operation succeeds.
|
||||
*/
|
||||
uint32_t SetTPMBootModeState(int developer_mode, int recovery_mode,
|
||||
uint64_t fw_keyblock_flags,
|
||||
GoogleBinaryBlockHeader *gbb);
|
||||
|
||||
#endif /* VBOOT_REFERENCE_TPM_BOOTMODE_H_ */
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
#include "cgptlib.h"
|
||||
#include "gpt_misc.h"
|
||||
#include "load_firmware_fw.h"
|
||||
#include "load_kernel_fw.h"
|
||||
#include "vboot_api.h"
|
||||
|
||||
|
||||
@@ -18,71 +18,23 @@ uint32_t SetVirtualDevMode(int val) {
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t TPMClearAndReenable(void) {
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t SetupTPM(int developer_mode, int disable_dev_request,
|
||||
int clear_tpm_owner_request, RollbackSpaceFirmware* rsf) {
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t RollbackS3Resume(void) {
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t RollbackFirmwareSetup(int is_hw_dev,
|
||||
int disable_dev_request,
|
||||
int clear_tpm_owner_request,
|
||||
int *is_virt_dev, uint32_t *version) {
|
||||
*version = 0;
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t RollbackFirmwareWrite(uint32_t version) {
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t RollbackFirmwareLock(void) {
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t RollbackKernelRead(uint32_t* version) {
|
||||
*version = 0;
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t RollbackKernelWrite(uint32_t version) {
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t RollbackKernelLock(int recovery_mode) {
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t rollback_backup[BACKUP_NV_SIZE];
|
||||
|
||||
uint32_t RollbackBackupRead(uint8_t *raw)
|
||||
{
|
||||
Memcpy(raw, rollback_backup, BACKUP_NV_SIZE);
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t RollbackBackupWrite(uint8_t *raw)
|
||||
{
|
||||
Memcpy(rollback_backup, raw, BACKUP_NV_SIZE);
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t RollbackFwmpRead(struct RollbackSpaceFwmp *fwmp)
|
||||
{
|
||||
Memset(fwmp, 0, sizeof(*fwmp));
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/* 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
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Functions for updating the TPM state with the status of boot path.
|
||||
*/
|
||||
|
||||
#include "sysincludes.h"
|
||||
|
||||
#include "tpm_bootmode.h"
|
||||
#include "tss_constants.h"
|
||||
|
||||
const char* kBootStateSHA1Digests[] = {
|
||||
/* SHA1("\x00\x00\x00") */
|
||||
"\x29\xe2\xdc\xfb\xb1\x6f\x63\xbb\x02\x54\xdf\x75\x85\xa1\x5b\xb6"
|
||||
"\xfb\x5e\x92\x7d",
|
||||
|
||||
/* SHA1("\x00\x00\x01") */
|
||||
"\x25\x47\xcc\x73\x6e\x95\x1f\xa4\x91\x98\x53\xc4\x3a\xe8\x90\x86"
|
||||
"\x1a\x3b\x32\x64",
|
||||
|
||||
/* SHA1("\x00\x00\x02") */
|
||||
"\x1e\xf6\x24\x48\x2d\x62\x0e\x43\xe6\xd3\x4d\xa1\xaf\xe4\x62\x67"
|
||||
"\xfc\x69\x5d\x9b",
|
||||
|
||||
/* SHA1("\x00\x01\x00") */
|
||||
"\x62\x57\x18\x91\x21\x5b\x4e\xfc\x1c\xea\xb7\x44\xce\x59\xdd\x0b"
|
||||
"\x66\xea\x6f\x73",
|
||||
|
||||
/* SHA1("\x00\x01\x01") */
|
||||
"\xee\xe4\x47\xed\xc7\x9f\xea\x1c\xa7\xc7\xd3\x4e\x46\x32\x61\xcd"
|
||||
"\xa4\xba\x33\x9e",
|
||||
|
||||
/* SHA1("\x00\x01\x02") */
|
||||
"\x0c\x7a\x62\x3f\xd2\xbb\xc0\x5b\x06\x42\x3b\xe3\x59\xe4\x02\x1d"
|
||||
"\x36\xe7\x21\xad",
|
||||
|
||||
/* SHA1("\x01\x00\x00") */
|
||||
"\x95\x08\xe9\x05\x48\xb0\x44\x0a\x4a\x61\xe5\x74\x3b\x76\xc1\xe3"
|
||||
"\x09\xb2\x3b\x7f",
|
||||
|
||||
/* SHA1("\x01\x00\x01") */
|
||||
"\xc4\x2a\xc1\xc4\x6f\x1d\x4e\x21\x1c\x73\x5c\xc7\xdf\xad\x4f\xf8"
|
||||
"\x39\x11\x10\xe9",
|
||||
|
||||
/* SHA1("\x01\x00\x02") */
|
||||
"\xfa\x01\x0d\x26\x64\xcc\x5b\x3b\x82\xee\x48\x8f\xe2\xb9\xf5\x0f"
|
||||
"\x49\x32\xeb\x8f",
|
||||
|
||||
/* SHA1("\x01\x01\x00") */
|
||||
"\x47\xec\x8d\x98\x36\x64\x33\xdc\x00\x2e\x77\x21\xc9\xe3\x7d\x50"
|
||||
"\x67\x54\x79\x37",
|
||||
|
||||
/* SHA1("\x01\x01\x01") */
|
||||
"\x28\xd8\x6c\x56\xb3\xbf\x26\xd2\x36\x56\x9b\x8d\xc8\xc3\xf9\x1f"
|
||||
"\x32\xf4\x7b\xc7",
|
||||
|
||||
/* SHA1("\x01\x01\x02") */
|
||||
"\x12\xa3\x40\xd7\x89\x7f\xe7\x13\xfc\x8f\x02\xac\x53\x65\xb8\x6e"
|
||||
"\xbf\x35\x31\x78",
|
||||
};
|
||||
|
||||
|
||||
uint32_t SetTPMBootModeState(int developer_mode, int recovery_mode,
|
||||
uint64_t fw_keyblock_flags,
|
||||
GoogleBinaryBlockHeader *gbb)
|
||||
{
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
@@ -69,17 +69,6 @@ uint32_t SafeWrite(uint32_t index, const void *data, uint32_t length)
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size)
|
||||
{
|
||||
uint32_t result = TlclDefineSpace(index, perm, size);
|
||||
if (result == TPM_E_MAXNVWRITES) {
|
||||
RETURN_ON_FAILURE(TPMClearAndReenable());
|
||||
return TlclDefineSpace(index, perm, size);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/* Functions to read and write firmware and kernel spaces. */
|
||||
uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf)
|
||||
{
|
||||
@@ -167,7 +156,7 @@ uint32_t SetVirtualDevMode(int val)
|
||||
rsf.flags &= ~FLAG_VIRTUAL_DEV_MODE_ON;
|
||||
/*
|
||||
* NOTE: This doesn't update the FLAG_LAST_BOOT_DEVELOPER bit. That
|
||||
* will be done by SetupTPM() on the next boot.
|
||||
* will be done on the next boot.
|
||||
*/
|
||||
VBDEBUG(("TPM: flags are now 0x%02x\n", rsf.flags));
|
||||
|
||||
@@ -247,293 +236,9 @@ uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk)
|
||||
return TPM_E_CORRUPTED_STATE;
|
||||
}
|
||||
|
||||
#ifndef TPM2_MODE
|
||||
uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware *rsf,
|
||||
RollbackSpaceKernel *rsk)
|
||||
{
|
||||
static const RollbackSpaceFirmware rsf_init = {
|
||||
.struct_version = ROLLBACK_SPACE_FIRMWARE_VERSION,
|
||||
};
|
||||
static const RollbackSpaceKernel rsk_init = {
|
||||
.struct_version = ROLLBACK_SPACE_KERNEL_VERSION,
|
||||
.uid = ROLLBACK_SPACE_KERNEL_UID,
|
||||
};
|
||||
TPM_PERMANENT_FLAGS pflags;
|
||||
uint32_t result;
|
||||
|
||||
VBDEBUG(("TPM: One-time initialization\n"));
|
||||
|
||||
/*
|
||||
* Do a full test. This only happens the first time the device is
|
||||
* turned on in the factory, so performance is not an issue. This is
|
||||
* almost certainly not necessary, but it gives us more confidence
|
||||
* about some code paths below that are difficult to
|
||||
* test---specifically the ones that set lifetime flags, and are only
|
||||
* executed once per physical TPM.
|
||||
*/
|
||||
result = TlclSelfTestFull();
|
||||
if (result != TPM_SUCCESS)
|
||||
return result;
|
||||
|
||||
result = TlclGetPermanentFlags(&pflags);
|
||||
if (result != TPM_SUCCESS)
|
||||
return result;
|
||||
|
||||
/*
|
||||
* TPM may come from the factory without physical presence finalized.
|
||||
* Fix if necessary.
|
||||
*/
|
||||
VBDEBUG(("TPM: physicalPresenceLifetimeLock=%d\n",
|
||||
pflags.physicalPresenceLifetimeLock));
|
||||
if (!pflags.physicalPresenceLifetimeLock) {
|
||||
VBDEBUG(("TPM: Finalizing physical presence\n"));
|
||||
RETURN_ON_FAILURE(TlclFinalizePhysicalPresence());
|
||||
}
|
||||
|
||||
/*
|
||||
* The TPM will not enforce the NV authorization restrictions until the
|
||||
* execution of a TPM_NV_DefineSpace with the handle of
|
||||
* TPM_NV_INDEX_LOCK. Here we create that space if it doesn't already
|
||||
* exist. */
|
||||
VBDEBUG(("TPM: nvLocked=%d\n", pflags.nvLocked));
|
||||
if (!pflags.nvLocked) {
|
||||
VBDEBUG(("TPM: Enabling NV locking\n"));
|
||||
RETURN_ON_FAILURE(TlclSetNvLocked());
|
||||
}
|
||||
|
||||
/* Clear TPM owner, in case the TPM is already owned for some reason. */
|
||||
VBDEBUG(("TPM: Clearing owner\n"));
|
||||
RETURN_ON_FAILURE(TPMClearAndReenable());
|
||||
|
||||
/* Initializes the firmware and kernel spaces */
|
||||
Memcpy(rsf, &rsf_init, sizeof(RollbackSpaceFirmware));
|
||||
Memcpy(rsk, &rsk_init, sizeof(RollbackSpaceKernel));
|
||||
|
||||
/* Define the backup space. No need to initialize it, though. */
|
||||
RETURN_ON_FAILURE(SafeDefineSpace(
|
||||
BACKUP_NV_INDEX, TPM_NV_PER_PPWRITE, BACKUP_NV_SIZE));
|
||||
|
||||
/* Define and initialize the kernel space */
|
||||
RETURN_ON_FAILURE(SafeDefineSpace(KERNEL_NV_INDEX, TPM_NV_PER_PPWRITE,
|
||||
sizeof(RollbackSpaceKernel)));
|
||||
RETURN_ON_FAILURE(WriteSpaceKernel(rsk));
|
||||
|
||||
/* Do the firmware space last, so we retry if we don't get this far. */
|
||||
RETURN_ON_FAILURE(SafeDefineSpace(
|
||||
FIRMWARE_NV_INDEX,
|
||||
TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE,
|
||||
sizeof(RollbackSpaceFirmware)));
|
||||
RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
|
||||
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* SetupTPM starts the TPM and establishes the root of trust for the
|
||||
* anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a
|
||||
* TPM hardware failure. 3 An unexpected TPM state due to some attack. In
|
||||
* general we cannot easily distinguish the kind of failure, so our strategy is
|
||||
* to reboot in recovery mode in all cases. The recovery mode calls SetupTPM
|
||||
* again, which executes (almost) the same sequence of operations. There is a
|
||||
* good chance that, if recovery mode was entered because of a TPM failure, the
|
||||
* failure will repeat itself. (In general this is impossible to guarantee
|
||||
* because we have no way of creating the exact TPM initial state at the
|
||||
* previous boot.) In recovery mode, we ignore the failure and continue, thus
|
||||
* giving the recovery kernel a chance to fix things (that's why we don't set
|
||||
* bGlobalLock). The choice is between a knowingly insecure device and a
|
||||
* bricked device.
|
||||
*
|
||||
* As a side note, observe that we go through considerable hoops to avoid using
|
||||
* the STCLEAR permissions for the index spaces. We do this to avoid writing
|
||||
* to the TPM flashram at every reboot or wake-up, because of concerns about
|
||||
* the durability of the NVRAM.
|
||||
*/
|
||||
uint32_t SetupTPM(int developer_mode, int disable_dev_request,
|
||||
int clear_tpm_owner_request, RollbackSpaceFirmware* rsf)
|
||||
{
|
||||
uint8_t in_flags;
|
||||
#ifndef TPM2_MODE
|
||||
uint8_t disable;
|
||||
uint8_t deactivated;
|
||||
#endif
|
||||
uint32_t result;
|
||||
uint32_t versions;
|
||||
|
||||
RETURN_ON_FAILURE(TlclLibInit());
|
||||
|
||||
#ifdef TEGRA_SOFT_REBOOT_WORKAROUND
|
||||
result = TlclStartup();
|
||||
if (result == TPM_E_INVALID_POSTINIT) {
|
||||
/*
|
||||
* Some prototype hardware doesn't reset the TPM on a CPU
|
||||
* reset. We do a hard reset to get around this.
|
||||
*/
|
||||
VBDEBUG(("TPM: soft reset detected\n", result));
|
||||
return TPM_E_MUST_REBOOT;
|
||||
} else if (result != TPM_SUCCESS) {
|
||||
VBDEBUG(("TPM: TlclStartup returned %08x\n", result));
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
RETURN_ON_FAILURE(TlclStartup());
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some TPMs start the self test automatically at power on. In that case we
|
||||
* don't need to call ContinueSelfTest. On some (other) TPMs,
|
||||
* ContinueSelfTest may block. In that case, we definitely don't want to
|
||||
* call it here. For TPMs in the intersection of these two sets, we're
|
||||
* screwed. (In other words: TPMs that require manually starting the
|
||||
* self-test AND block will have poor performance until we split
|
||||
* TlclSendReceive() into Send() and Receive(), and have a state machine to
|
||||
* control setup.)
|
||||
*
|
||||
* This comment is likely to become obsolete in the near future, so don't
|
||||
* trust it. It may have not been updated.
|
||||
*/
|
||||
#ifdef TPM_MANUAL_SELFTEST
|
||||
#ifdef TPM_BLOCKING_CONTINUESELFTEST
|
||||
#warning "lousy TPM!"
|
||||
#endif
|
||||
RETURN_ON_FAILURE(TlclContinueSelfTest());
|
||||
#endif
|
||||
#ifndef TPM2_MODE
|
||||
result = TlclAssertPhysicalPresence();
|
||||
if (result != TPM_SUCCESS) {
|
||||
/*
|
||||
* It is possible that the TPM was delivered with the physical
|
||||
* presence command disabled. This tries enabling it, then
|
||||
* tries asserting PP again.
|
||||
*/
|
||||
RETURN_ON_FAILURE(TlclPhysicalPresenceCMDEnable());
|
||||
RETURN_ON_FAILURE(TlclAssertPhysicalPresence());
|
||||
}
|
||||
|
||||
/* Check that the TPM is enabled and activated. */
|
||||
RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated, NULL));
|
||||
if (disable || deactivated) {
|
||||
VBDEBUG(("TPM: disabled (%d) or deactivated (%d). Fixing...\n",
|
||||
disable, deactivated));
|
||||
RETURN_ON_FAILURE(TlclSetEnable());
|
||||
RETURN_ON_FAILURE(TlclSetDeactivated(0));
|
||||
VBDEBUG(("TPM: Must reboot to re-enable\n"));
|
||||
return TPM_E_MUST_REBOOT;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Read the firmware space. */
|
||||
result = ReadSpaceFirmware(rsf);
|
||||
#ifndef TPM2_MODE
|
||||
if (TPM_E_BADINDEX == result) {
|
||||
RollbackSpaceKernel rsk;
|
||||
|
||||
/*
|
||||
* This is the first time we've run, and the TPM has not been
|
||||
* initialized. Initialize it.
|
||||
*/
|
||||
VBDEBUG(("TPM: Not initialized yet.\n"));
|
||||
RETURN_ON_FAILURE(OneTimeInitializeTPM(rsf, &rsk));
|
||||
} else
|
||||
#endif
|
||||
if (TPM_SUCCESS != result) {
|
||||
VBDEBUG(("TPM: Firmware space in a bad state; giving up.\n"));
|
||||
return TPM_E_CORRUPTED_STATE;
|
||||
}
|
||||
Memcpy(&versions, &rsf->fw_versions, sizeof(versions));
|
||||
VBDEBUG(("TPM: Firmware space sv%d f%x v%x\n",
|
||||
rsf->struct_version, rsf->flags, versions));
|
||||
in_flags = rsf->flags;
|
||||
|
||||
/* If we've been asked to clear the virtual dev-mode flag, do so now */
|
||||
if (disable_dev_request) {
|
||||
rsf->flags &= ~FLAG_VIRTUAL_DEV_MODE_ON;
|
||||
VBDEBUG(("TPM: Clearing virt dev-switch: f%x\n", rsf->flags));
|
||||
}
|
||||
|
||||
/*
|
||||
* The developer_mode value that's passed in is only set by a hardware
|
||||
* dev-switch. We should OR it with the virtual switch, whether or not
|
||||
* the virtual switch is used. If it's not used, it shouldn't change,
|
||||
* so it doesn't matter.
|
||||
*/
|
||||
if (rsf->flags & FLAG_VIRTUAL_DEV_MODE_ON)
|
||||
developer_mode = 1;
|
||||
|
||||
/*
|
||||
* Clear ownership if developer flag has toggled, or if an owner-clear
|
||||
* has been requested.
|
||||
*/
|
||||
if ((developer_mode ? FLAG_LAST_BOOT_DEVELOPER : 0) !=
|
||||
(in_flags & FLAG_LAST_BOOT_DEVELOPER)) {
|
||||
VBDEBUG(("TPM: Developer flag changed; clearing owner.\n"));
|
||||
RETURN_ON_FAILURE(TPMClearAndReenable());
|
||||
} else if (clear_tpm_owner_request) {
|
||||
VBDEBUG(("TPM: Clearing owner as specifically requested.\n"));
|
||||
RETURN_ON_FAILURE(TPMClearAndReenable());
|
||||
}
|
||||
|
||||
if (developer_mode)
|
||||
rsf->flags |= FLAG_LAST_BOOT_DEVELOPER;
|
||||
else
|
||||
rsf->flags &= ~FLAG_LAST_BOOT_DEVELOPER;
|
||||
|
||||
|
||||
/* If firmware space is dirty, flush it back to the TPM */
|
||||
if (rsf->flags != in_flags) {
|
||||
VBDEBUG(("TPM: Updating firmware space.\n"));
|
||||
RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
|
||||
}
|
||||
|
||||
VBDEBUG(("TPM: SetupTPM() succeeded\n"));
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef DISABLE_ROLLBACK_TPM
|
||||
/* Dummy implementations which don't support TPM rollback protection */
|
||||
|
||||
uint32_t RollbackS3Resume(void)
|
||||
{
|
||||
#ifndef CHROMEOS_ENVIRONMENT
|
||||
/*
|
||||
* Initialize the TPM, but ignore return codes. In ChromeOS
|
||||
* environment, don't even talk to the TPM.
|
||||
*/
|
||||
TlclLibInit();
|
||||
TlclResume();
|
||||
#endif
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t RollbackFirmwareSetup(int is_hw_dev,
|
||||
int disable_dev_request,
|
||||
int clear_tpm_owner_request,
|
||||
int *is_virt_dev, uint32_t *version)
|
||||
{
|
||||
#ifndef CHROMEOS_ENVIRONMENT
|
||||
/*
|
||||
* Initialize the TPM, but ignores return codes. In ChromeOS
|
||||
* environment, don't even talk to the TPM.
|
||||
*/
|
||||
TlclLibInit();
|
||||
TlclStartup();
|
||||
TlclContinueSelfTest();
|
||||
#endif
|
||||
*is_virt_dev = 0;
|
||||
*version = 0;
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t RollbackFirmwareWrite(uint32_t version)
|
||||
{
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t RollbackFirmwareLock(void)
|
||||
{
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t RollbackKernelRead(uint32_t* version)
|
||||
{
|
||||
*version = 0;
|
||||
@@ -545,16 +250,6 @@ uint32_t RollbackKernelWrite(uint32_t version)
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t RollbackBackupRead(uint8_t *raw)
|
||||
{
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t RollbackBackupWrite(uint8_t *raw)
|
||||
{
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t RollbackKernelLock(int recovery_mode)
|
||||
{
|
||||
return TPM_SUCCESS;
|
||||
@@ -568,57 +263,6 @@ uint32_t RollbackFwmpRead(struct RollbackSpaceFwmp *fwmp)
|
||||
|
||||
#else
|
||||
|
||||
uint32_t RollbackS3Resume(void)
|
||||
{
|
||||
uint32_t result;
|
||||
RETURN_ON_FAILURE(TlclLibInit());
|
||||
result = TlclResume();
|
||||
if (result == TPM_E_INVALID_POSTINIT) {
|
||||
/*
|
||||
* We're on a platform where the TPM maintains power in S3, so
|
||||
* it's already initialized.
|
||||
*/
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t RollbackFirmwareSetup(int is_hw_dev,
|
||||
int disable_dev_request,
|
||||
int clear_tpm_owner_request,
|
||||
int *is_virt_dev, uint32_t *version)
|
||||
{
|
||||
RollbackSpaceFirmware rsf;
|
||||
|
||||
/* Set version to 0 in case we fail */
|
||||
*version = 0;
|
||||
|
||||
RETURN_ON_FAILURE(SetupTPM(is_hw_dev, disable_dev_request,
|
||||
clear_tpm_owner_request, &rsf));
|
||||
Memcpy(version, &rsf.fw_versions, sizeof(*version));
|
||||
*is_virt_dev = (rsf.flags & FLAG_VIRTUAL_DEV_MODE_ON) ? 1 : 0;
|
||||
VBDEBUG(("TPM: RollbackFirmwareSetup %x\n", (int)*version));
|
||||
return TPM_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t RollbackFirmwareWrite(uint32_t version)
|
||||
{
|
||||
RollbackSpaceFirmware rsf;
|
||||
uint32_t old_version;
|
||||
|
||||
RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf));
|
||||
Memcpy(&old_version, &rsf.fw_versions, sizeof(old_version));
|
||||
VBDEBUG(("TPM: RollbackFirmwareWrite %x --> %x\n", (int)old_version,
|
||||
(int)version));
|
||||
Memcpy(&rsf.fw_versions, &version, sizeof(version));
|
||||
return WriteSpaceFirmware(&rsf);
|
||||
}
|
||||
|
||||
uint32_t RollbackFirmwareLock(void)
|
||||
{
|
||||
return TlclSetGlobalLock();
|
||||
}
|
||||
|
||||
uint32_t RollbackKernelRead(uint32_t* version)
|
||||
{
|
||||
RollbackSpaceKernel rsk;
|
||||
@@ -664,29 +308,6 @@ uint32_t RollbackKernelWrite(uint32_t version)
|
||||
return WriteSpaceKernel(&rsk);
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't really care whether the TPM owner has been messing with this or
|
||||
* not. We lock it along with the Kernel space just to avoid problems, but it's
|
||||
* only useful in dev-mode and only when the battery has been drained
|
||||
* completely. There aren't any security issues. It's just in the TPM because
|
||||
* we don't have any other place to keep it.
|
||||
*/
|
||||
uint32_t RollbackBackupRead(uint8_t *raw)
|
||||
{
|
||||
uint32_t r;
|
||||
r = TlclRead(BACKUP_NV_INDEX, raw, BACKUP_NV_SIZE);
|
||||
VBDEBUG(("TPM: %s returning 0x%x\n", __func__, r));
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32_t RollbackBackupWrite(uint8_t *raw)
|
||||
{
|
||||
uint32_t r;
|
||||
r = TlclWrite(BACKUP_NV_INDEX, raw, BACKUP_NV_SIZE);
|
||||
VBDEBUG(("TPM: %s returning 0x%x\n", __func__, r));
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32_t RollbackKernelLock(int recovery_mode)
|
||||
{
|
||||
static int kernel_locked = 0;
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Functions for updating the TPM state with the status of boot path.
|
||||
*/
|
||||
|
||||
#include "sysincludes.h"
|
||||
|
||||
#include "tlcl.h"
|
||||
#include "tpm_bootmode.h"
|
||||
#include "utility.h"
|
||||
#include "vboot_api.h"
|
||||
|
||||
/* TPM PCRs to use for storing boot mode measurements. */
|
||||
#define BOOT_MODE_PCR 0
|
||||
#define HWID_DIGEST_PCR 1
|
||||
|
||||
/*
|
||||
* Input digests for PCR extend.
|
||||
* These are calculated as:
|
||||
* SHA1("|Developer_Mode||Recovery_Mode||Keyblock_Mode|").
|
||||
* Developer_Mode can be 0 or 1.
|
||||
* Recovery_Mode can be 0 or 1.
|
||||
* Keyblock flags are defined in vboot_struct.h
|
||||
*
|
||||
* We map them to Keyblock_Mode as follows:
|
||||
* -----------------------------------------
|
||||
* Keyblock Flags | Keyblock Mode
|
||||
* -----------------------------------------
|
||||
* 6 (Dev-signed firmware) | 2
|
||||
* 7 Normal-signed firmware | 1
|
||||
* (anything else) | 0
|
||||
*/
|
||||
|
||||
const char* kBootStateSHA1Digests[] = {
|
||||
/* SHA1("\x00\x00\x00") */
|
||||
"\x29\xe2\xdc\xfb\xb1\x6f\x63\xbb\x02\x54\xdf\x75\x85\xa1\x5b\xb6"
|
||||
"\xfb\x5e\x92\x7d",
|
||||
|
||||
/* SHA1("\x00\x00\x01") */
|
||||
"\x25\x47\xcc\x73\x6e\x95\x1f\xa4\x91\x98\x53\xc4\x3a\xe8\x90\x86"
|
||||
"\x1a\x3b\x32\x64",
|
||||
|
||||
/* SHA1("\x00\x00\x02") */
|
||||
"\x1e\xf6\x24\x48\x2d\x62\x0e\x43\xe6\xd3\x4d\xa1\xaf\xe4\x62\x67"
|
||||
"\xfc\x69\x5d\x9b",
|
||||
|
||||
/* SHA1("\x00\x01\x00") */
|
||||
"\x62\x57\x18\x91\x21\x5b\x4e\xfc\x1c\xea\xb7\x44\xce\x59\xdd\x0b"
|
||||
"\x66\xea\x6f\x73",
|
||||
|
||||
/* SHA1("\x00\x01\x01") */
|
||||
"\xee\xe4\x47\xed\xc7\x9f\xea\x1c\xa7\xc7\xd3\x4e\x46\x32\x61\xcd"
|
||||
"\xa4\xba\x33\x9e",
|
||||
|
||||
/* SHA1("\x00\x01\x02") */
|
||||
"\x0c\x7a\x62\x3f\xd2\xbb\xc0\x5b\x06\x42\x3b\xe3\x59\xe4\x02\x1d"
|
||||
"\x36\xe7\x21\xad",
|
||||
|
||||
/* SHA1("\x01\x00\x00") */
|
||||
"\x95\x08\xe9\x05\x48\xb0\x44\x0a\x4a\x61\xe5\x74\x3b\x76\xc1\xe3"
|
||||
"\x09\xb2\x3b\x7f",
|
||||
|
||||
/* SHA1("\x01\x00\x01") */
|
||||
"\xc4\x2a\xc1\xc4\x6f\x1d\x4e\x21\x1c\x73\x5c\xc7\xdf\xad\x4f\xf8"
|
||||
"\x39\x11\x10\xe9",
|
||||
|
||||
/* SHA1("\x01\x00\x02") */
|
||||
"\xfa\x01\x0d\x26\x64\xcc\x5b\x3b\x82\xee\x48\x8f\xe2\xb9\xf5\x0f"
|
||||
"\x49\x32\xeb\x8f",
|
||||
|
||||
/* SHA1("\x01\x01\x00") */
|
||||
"\x47\xec\x8d\x98\x36\x64\x33\xdc\x00\x2e\x77\x21\xc9\xe3\x7d\x50"
|
||||
"\x67\x54\x79\x37",
|
||||
|
||||
/* SHA1("\x01\x01\x01") */
|
||||
"\x28\xd8\x6c\x56\xb3\xbf\x26\xd2\x36\x56\x9b\x8d\xc8\xc3\xf9\x1f"
|
||||
"\x32\xf4\x7b\xc7",
|
||||
|
||||
/* SHA1("\x01\x01\x02") */
|
||||
"\x12\xa3\x40\xd7\x89\x7f\xe7\x13\xfc\x8f\x02\xac\x53\x65\xb8\x6e"
|
||||
"\xbf\x35\x31\x78",
|
||||
};
|
||||
|
||||
#define MAX_BOOT_STATE_INDEX (sizeof(kBootStateSHA1Digests)/sizeof(char *))
|
||||
|
||||
/*
|
||||
* Used for PCR extend when the passed-in boot state is invalid or if there is
|
||||
* an internal error.
|
||||
*/
|
||||
const uint8_t kBootInvalidSHA1Digest[] = {
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
"\xff\xff\xff\xff"
|
||||
};
|
||||
|
||||
/**
|
||||
* Given the boot state, return the correct SHA1 digest index for TPMExtend
|
||||
* in kBootStateSHA1Digests[].
|
||||
*/
|
||||
static int GetBootStateIndex(int dev_mode, int rec_mode,
|
||||
uint64_t keyblock_flags)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
/*
|
||||
* Convert keyblock flags into keyblock mode which we use to index into
|
||||
* kBootStateSHA1Digest[].
|
||||
*/
|
||||
switch(keyblock_flags) {
|
||||
case 6:
|
||||
/*
|
||||
* KEY_BLOCK_FLAG_RECOVERY_0 | KEY_BLOCK_FLAG_DEVELOPER_1
|
||||
*
|
||||
* Developer firmware. */
|
||||
index = 2;
|
||||
break;
|
||||
case 7:
|
||||
/*
|
||||
* KEY_BLOCK_FLAG_RECOVERY_0 | KEY_BLOCK_FLAG_DEVELOPER_0
|
||||
* | KEY_BLOCK_FLAGS_DEVELOPER_1
|
||||
*/
|
||||
index = 1;
|
||||
break;
|
||||
default:
|
||||
/* Any other keyblock flags. */
|
||||
index = 0;
|
||||
};
|
||||
|
||||
if (rec_mode)
|
||||
index += 3;
|
||||
if (dev_mode)
|
||||
index += 6;
|
||||
return index;
|
||||
}
|
||||
|
||||
uint32_t SetTPMBootModeState(int developer_mode, int recovery_mode,
|
||||
uint64_t fw_keyblock_flags,
|
||||
GoogleBinaryBlockHeader *gbb)
|
||||
{
|
||||
uint32_t result0, result1 = 0;
|
||||
const uint8_t *in_digest = NULL;
|
||||
uint8_t out_digest[20]; /* For PCR extend output. */
|
||||
int digest_index = GetBootStateIndex(developer_mode, recovery_mode,
|
||||
fw_keyblock_flags);
|
||||
|
||||
if (digest_index >= 0 && digest_index < MAX_BOOT_STATE_INDEX) {
|
||||
in_digest = (const uint8_t*)
|
||||
kBootStateSHA1Digests[digest_index];
|
||||
} else {
|
||||
/* Internal out of bounds error. */
|
||||
in_digest = kBootInvalidSHA1Digest;
|
||||
}
|
||||
|
||||
result0 = TlclExtend(BOOT_MODE_PCR, in_digest, out_digest);
|
||||
VBDEBUG(("TPM: SetTPMBootModeState boot mode PCR%d result %d\n",
|
||||
BOOT_MODE_PCR, result0));
|
||||
|
||||
/* Extend the HWID Digest into PCR1 (GBB v1.2 and later only) */
|
||||
if (gbb && gbb->minor_version >= 2) {
|
||||
result1 = TlclExtend(HWID_DIGEST_PCR, gbb->hwid_digest,
|
||||
out_digest);
|
||||
VBDEBUG(("TPM: SetTPMBootModeState HWID PCR%d result %d\n",
|
||||
HWID_DIGEST_PCR, result1));
|
||||
}
|
||||
|
||||
/* The caller only looks for nonzero results, not error codes. */
|
||||
return result0 || result1;
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* High-level firmware wrapper API - entry points for init, firmware selection
|
||||
*/
|
||||
|
||||
#include "sysincludes.h"
|
||||
|
||||
#include "gbb_access.h"
|
||||
#include "gbb_header.h"
|
||||
#include "load_firmware_fw.h"
|
||||
#include "rollback_index.h"
|
||||
#include "tpm_bootmode.h"
|
||||
#include "utility.h"
|
||||
#include "vboot_api.h"
|
||||
#include "vboot_common.h"
|
||||
#include "vboot_nvstorage.h"
|
||||
|
||||
VbError_t VbSelectFirmware(VbCommonParams *cparams,
|
||||
VbSelectFirmwareParams *fparams)
|
||||
{
|
||||
VbSharedDataHeader *shared =
|
||||
(VbSharedDataHeader *)cparams->shared_data_blob;
|
||||
VbNvContext vnc;
|
||||
VbError_t retval = VBERROR_UNKNOWN; /* Default to error */
|
||||
int is_rec = (shared->recovery_reason ? 1 : 0);
|
||||
int is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0);
|
||||
uint32_t tpm_status = 0;
|
||||
|
||||
cparams->gbb = NULL;
|
||||
cparams->bmp = NULL;
|
||||
|
||||
/* Start timer */
|
||||
shared->timer_vb_select_firmware_enter = VbExGetTimer();
|
||||
|
||||
/* Load NV storage */
|
||||
VbExNvStorageRead(vnc.raw);
|
||||
VbNvSetup(&vnc);
|
||||
|
||||
if (is_rec) {
|
||||
/*
|
||||
* Recovery is requested; go straight to recovery without
|
||||
* checking the RW firmware.
|
||||
*/
|
||||
VBDEBUG(("VbSelectFirmware() detected recovery request\n"));
|
||||
|
||||
/* Best effort to read the GBB */
|
||||
cparams->gbb = VbExMalloc(sizeof(*cparams->gbb));
|
||||
retval = VbGbbReadHeader_static(cparams, cparams->gbb);
|
||||
if (VBERROR_SUCCESS != retval) {
|
||||
VBDEBUG(("Can't read GBB. Continuing anyway...\n"));
|
||||
VbExFree(cparams->gbb);
|
||||
cparams->gbb = NULL;
|
||||
}
|
||||
|
||||
/* Go directly to recovery mode */
|
||||
fparams->selected_firmware = VB_SELECT_FIRMWARE_RECOVERY;
|
||||
} else {
|
||||
cparams->gbb = VbExMalloc(sizeof(*cparams->gbb));
|
||||
retval = VbGbbReadHeader_static(cparams, cparams->gbb);
|
||||
if (VBERROR_SUCCESS != retval)
|
||||
goto VbSelectFirmware_exit;
|
||||
|
||||
/* Chain to LoadFirmware() */
|
||||
retval = LoadFirmware(cparams, fparams, &vnc);
|
||||
|
||||
/* Exit if we failed to find an acceptable firmware */
|
||||
if (VBERROR_SUCCESS != retval)
|
||||
goto VbSelectFirmware_exit;
|
||||
|
||||
/* Translate the selected firmware path */
|
||||
if (shared->flags & VBSD_LF_USE_RO_NORMAL) {
|
||||
/* Request the read-only normal/dev code path */
|
||||
fparams->selected_firmware =
|
||||
VB_SELECT_FIRMWARE_READONLY;
|
||||
} else if (0 == shared->firmware_index)
|
||||
fparams->selected_firmware = VB_SELECT_FIRMWARE_A;
|
||||
else {
|
||||
fparams->selected_firmware = VB_SELECT_FIRMWARE_B;
|
||||
}
|
||||
|
||||
/* Update TPM if necessary */
|
||||
if (shared->fw_version_tpm_start < shared->fw_version_tpm) {
|
||||
tpm_status =
|
||||
RollbackFirmwareWrite(shared->fw_version_tpm);
|
||||
if (0 != tpm_status) {
|
||||
VBDEBUG(("Can't write FW version to TPM.\n"));
|
||||
VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
|
||||
VBNV_RECOVERY_RO_TPM_W_ERROR);
|
||||
retval = VBERROR_TPM_WRITE_FIRMWARE;
|
||||
goto VbSelectFirmware_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Lock firmware versions in TPM */
|
||||
tpm_status = RollbackFirmwareLock();
|
||||
if (0 != tpm_status) {
|
||||
VBDEBUG(("Unable to lock firmware version in TPM.\n"));
|
||||
VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
|
||||
VBNV_RECOVERY_RO_TPM_L_ERROR);
|
||||
retval = VBERROR_TPM_LOCK_FIRMWARE;
|
||||
goto VbSelectFirmware_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, we have a good idea of how we are going to
|
||||
* boot. Update the TPM with this state information.
|
||||
*/
|
||||
tpm_status = SetTPMBootModeState(is_dev, is_rec,
|
||||
shared->fw_keyblock_flags,
|
||||
cparams->gbb);
|
||||
if (0 != tpm_status) {
|
||||
VBDEBUG(("Can't update the TPM with boot mode information.\n"));
|
||||
if (!is_rec) {
|
||||
VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
|
||||
VBNV_RECOVERY_RO_TPM_U_ERROR);
|
||||
retval = VBERROR_TPM_SET_BOOT_MODE_STATE;
|
||||
goto VbSelectFirmware_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Success! */
|
||||
retval = VBERROR_SUCCESS;
|
||||
|
||||
VbSelectFirmware_exit:
|
||||
|
||||
if (cparams->gbb) {
|
||||
VbExFree(cparams->gbb);
|
||||
cparams->gbb = NULL;
|
||||
}
|
||||
|
||||
/* Save NV storage */
|
||||
VbNvTeardown(&vnc);
|
||||
if (vnc.raw_changed)
|
||||
VbExNvStorageWrite(vnc.raw);
|
||||
|
||||
/* Stop timer */
|
||||
shared->timer_vb_select_firmware_exit = VbExGetTimer();
|
||||
|
||||
/* Should always have a known error code */
|
||||
VbAssert(VBERROR_UNKNOWN != retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -1,378 +0,0 @@
|
||||
/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* High-level firmware wrapper API - entry points for init, firmware selection
|
||||
*/
|
||||
|
||||
#include "sysincludes.h"
|
||||
|
||||
#include "region.h"
|
||||
#include "gbb_access.h"
|
||||
#include "gbb_header.h"
|
||||
#include "load_firmware_fw.h"
|
||||
#include "rollback_index.h"
|
||||
#include "utility.h"
|
||||
#include "vboot_api.h"
|
||||
#include "vboot_common.h"
|
||||
#include "vboot_nvstorage.h"
|
||||
|
||||
VbError_t VbInit(VbCommonParams *cparams, VbInitParams *iparams)
|
||||
{
|
||||
VbSharedDataHeader *shared =
|
||||
(VbSharedDataHeader *)cparams->shared_data_blob;
|
||||
GoogleBinaryBlockHeader gbb;
|
||||
VbNvContext vnc;
|
||||
VbError_t retval = VBERROR_SUCCESS;
|
||||
uint32_t recovery = VBNV_RECOVERY_NOT_REQUESTED;
|
||||
int is_s3_resume = 0;
|
||||
uint32_t s3_debug_boot = 0;
|
||||
uint32_t require_official_os = 0;
|
||||
uint32_t tpm_version = 0;
|
||||
uint32_t tpm_status = 0;
|
||||
int has_virt_dev_switch = 0;
|
||||
int is_hw_dev = 0;
|
||||
int is_virt_dev = 0;
|
||||
uint32_t disable_dev_request = 0;
|
||||
uint32_t clear_tpm_owner_request = 0;
|
||||
int is_dev = 0;
|
||||
uint32_t backup_requested = 0;
|
||||
uint32_t backup_for_safety = 0;
|
||||
int lost_nvram;
|
||||
|
||||
/* Initialize output flags */
|
||||
iparams->out_flags = 0;
|
||||
|
||||
retval = VbGbbReadHeader_static(cparams, &gbb);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
VBDEBUG(("VbInit() input flags 0x%x gbb flags 0x%x\n", iparams->flags,
|
||||
gbb.flags));
|
||||
|
||||
/* Set up NV storage */
|
||||
VbExNvStorageRead(vnc.raw);
|
||||
VbNvSetup(&vnc);
|
||||
lost_nvram = vnc.regenerate_crc;
|
||||
|
||||
/* Initialize shared data structure */
|
||||
if (0 != VbSharedDataInit(shared, cparams->shared_data_size)) {
|
||||
VBDEBUG(("Shared data init error\n"));
|
||||
return VBERROR_INIT_SHARED_DATA;
|
||||
}
|
||||
|
||||
shared->timer_vb_init_enter = VbExGetTimer();
|
||||
|
||||
/* Copy some boot switch flags */
|
||||
/* TODO: in next refactor, just save in/out flags in VbSharedData */
|
||||
shared->flags = 0;
|
||||
if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED)
|
||||
shared->flags |= VBSD_BOOT_REC_SWITCH_ON;
|
||||
if (iparams->flags & VB_INIT_FLAG_WP_ENABLED)
|
||||
shared->flags |= VBSD_BOOT_FIRMWARE_WP_ENABLED;
|
||||
if (iparams->flags & VB_INIT_FLAG_SW_WP_ENABLED)
|
||||
shared->flags |= VBSD_BOOT_FIRMWARE_SW_WP_ENABLED;
|
||||
if (iparams->flags & VB_INIT_FLAG_S3_RESUME)
|
||||
shared->flags |= VBSD_BOOT_S3_RESUME;
|
||||
if (iparams->flags & VB_INIT_FLAG_RO_NORMAL_SUPPORT)
|
||||
shared->flags |= VBSD_BOOT_RO_NORMAL_SUPPORT;
|
||||
if (iparams->flags & VB_INIT_FLAG_NOFAIL_BOOT)
|
||||
shared->flags |= VBSD_NOFAIL_BOOT;
|
||||
if (iparams->flags & VB_INIT_FLAG_EC_SOFTWARE_SYNC)
|
||||
shared->flags |= VBSD_EC_SOFTWARE_SYNC;
|
||||
if (iparams->flags & VB_INIT_FLAG_EC_SLOW_UPDATE)
|
||||
shared->flags |= VBSD_EC_SLOW_UPDATE;
|
||||
if (iparams->flags & VB_INIT_FLAG_VIRTUAL_REC_SWITCH)
|
||||
shared->flags |= VBSD_BOOT_REC_SWITCH_VIRTUAL;
|
||||
if (iparams->flags & VB_INIT_FLAG_OPROM_MATTERS)
|
||||
shared->flags |= VBSD_OPROM_MATTERS;
|
||||
if (iparams->flags & VB_INIT_FLAG_OPROM_LOADED)
|
||||
shared->flags |= VBSD_OPROM_LOADED;
|
||||
|
||||
is_s3_resume = (iparams->flags & VB_INIT_FLAG_S3_RESUME ? 1 : 0);
|
||||
|
||||
/* Check if the OS is requesting a debug S3 reset */
|
||||
VbNvGet(&vnc, VBNV_DEBUG_RESET_MODE, &s3_debug_boot);
|
||||
if (s3_debug_boot) {
|
||||
if (is_s3_resume) {
|
||||
VBDEBUG(("VbInit() requesting S3 debug boot\n"));
|
||||
iparams->out_flags |= VB_INIT_OUT_S3_DEBUG_BOOT;
|
||||
is_s3_resume = 0; /* Proceed as if normal boot */
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the request even if this is a normal boot, since we
|
||||
* don't want the NEXT S3 resume to be a debug reset unless the
|
||||
* OS asserts the request again.
|
||||
*/
|
||||
VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this isn't a S3 resume, read the current recovery request, then
|
||||
* clear it so we don't get stuck in recovery mode.
|
||||
*/
|
||||
if (!is_s3_resume) {
|
||||
VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &recovery);
|
||||
VBDEBUG(("VbInit sees recovery request = %d\n", recovery));
|
||||
if (VBNV_RECOVERY_NOT_REQUESTED != recovery)
|
||||
VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
|
||||
VBNV_RECOVERY_NOT_REQUESTED);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the previous boot failed in the firmware somewhere outside of
|
||||
* verified boot, and recovery is not requested for our own reasons,
|
||||
* request recovery mode. This gives the calling firmware a way to
|
||||
* request recovery if it finds something terribly wrong.
|
||||
*/
|
||||
if (VBNV_RECOVERY_NOT_REQUESTED == recovery &&
|
||||
iparams->flags & VB_INIT_FLAG_PREVIOUS_BOOT_FAIL) {
|
||||
recovery = VBNV_RECOVERY_RO_FIRMWARE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If recovery button is pressed, override recovery reason. Note that
|
||||
* we do this in the S3 resume path also.
|
||||
*/
|
||||
if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED)
|
||||
recovery = VBNV_RECOVERY_RO_MANUAL;
|
||||
|
||||
/*
|
||||
* Copy current recovery reason to shared data. If we fail later on, it
|
||||
* won't matter, since we'll just reboot.
|
||||
*/
|
||||
shared->recovery_reason = (uint8_t)recovery;
|
||||
VBDEBUG(("VbInit now sets shared->recovery_reason = %d\n", recovery));
|
||||
|
||||
/*
|
||||
* If this is a S3 resume, resume the TPM.
|
||||
*
|
||||
* FIXME: I think U-Boot won't ever ask us to do this. Can we remove
|
||||
* it?
|
||||
*/
|
||||
if (is_s3_resume) {
|
||||
if (TPM_SUCCESS != RollbackS3Resume()) {
|
||||
/*
|
||||
* If we can't resume, just do a full reboot. No need
|
||||
* to go to recovery mode here, since if the TPM is
|
||||
* really broken we'll catch it on the next boot.
|
||||
*/
|
||||
retval = VBERROR_TPM_S3_RESUME;
|
||||
}
|
||||
} else {
|
||||
/* Should we pay attention to the TPM's virtual dev-switch? */
|
||||
if (iparams->flags & VB_INIT_FLAG_VIRTUAL_DEV_SWITCH) {
|
||||
shared->flags |= VBSD_HONOR_VIRT_DEV_SWITCH;
|
||||
has_virt_dev_switch = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We always believe the HW dev-switch, since there's one
|
||||
* attached to servo which may be active even on systems
|
||||
* without a physical switch. The EC may also implement a fake
|
||||
* dev-switch for testing.
|
||||
*/
|
||||
if (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON)
|
||||
is_hw_dev = 1;
|
||||
|
||||
/* We may be asked to clear the virtual dev-switch at boot. */
|
||||
VbNvGet(&vnc, VBNV_DISABLE_DEV_REQUEST, &disable_dev_request);
|
||||
|
||||
/* Allow GBB flag to override dev switch */
|
||||
if (gbb.flags & GBB_FLAG_FORCE_DEV_SWITCH_ON)
|
||||
is_hw_dev = 1;
|
||||
|
||||
/* Have we been explicitly asked to clear the TPM owner? */
|
||||
VbNvGet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST,
|
||||
&clear_tpm_owner_request);
|
||||
|
||||
/*
|
||||
* Initialize the TPM. If the developer mode state has changed
|
||||
* since the last boot, we need to clear TPM ownership. If the
|
||||
* TPM space is initialized by this call, the virtual
|
||||
* dev-switch will be disabled by default)
|
||||
*/
|
||||
VBDEBUG(("TPM: Call RollbackFirmwareSetup(r%d, d%d)\n",
|
||||
recovery, is_hw_dev));
|
||||
tpm_status = RollbackFirmwareSetup(is_hw_dev,
|
||||
disable_dev_request,
|
||||
clear_tpm_owner_request,
|
||||
/* two outputs on success */
|
||||
&is_virt_dev, &tpm_version);
|
||||
|
||||
if (0 != tpm_status) {
|
||||
VBDEBUG(("Unable to setup TPM and read "
|
||||
"firmware version (0x%x)\n", tpm_status));
|
||||
|
||||
if (TPM_E_MUST_REBOOT == tpm_status) {
|
||||
/*
|
||||
* TPM wants to reboot into the same mode we're
|
||||
* in now
|
||||
*/
|
||||
VBDEBUG(("TPM requires a reboot.\n"));
|
||||
if (!recovery) {
|
||||
/*
|
||||
* Not recovery mode. Just reboot (not
|
||||
* into recovery).
|
||||
*/
|
||||
retval = VBERROR_TPM_REBOOT_REQUIRED;
|
||||
goto VbInit_exit;
|
||||
} else if (VBNV_RECOVERY_RO_TPM_REBOOT !=
|
||||
shared->recovery_reason) {
|
||||
/*
|
||||
* In recovery mode now, and we haven't
|
||||
* requested a TPM reboot yet, so
|
||||
* request one.
|
||||
*/
|
||||
VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
|
||||
VBNV_RECOVERY_RO_TPM_REBOOT);
|
||||
retval = VBERROR_TPM_REBOOT_REQUIRED;
|
||||
goto VbInit_exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (!recovery) {
|
||||
VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
|
||||
VBNV_RECOVERY_RO_TPM_S_ERROR);
|
||||
VbNvSet(&vnc, VBNV_RECOVERY_SUBCODE,
|
||||
tpm_status);
|
||||
retval = VBERROR_TPM_FIRMWARE_SETUP;
|
||||
goto VbInit_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* TPM setup succeeded, or we're in recovery mode and ignoring
|
||||
* errors. What did we learn? */
|
||||
shared->fw_version_tpm_start = tpm_version;
|
||||
shared->fw_version_tpm = tpm_version;
|
||||
if (is_hw_dev || (has_virt_dev_switch && is_virt_dev)) {
|
||||
is_dev = 1;
|
||||
shared->flags |= VBSD_BOOT_DEV_SWITCH_ON;
|
||||
}
|
||||
if (disable_dev_request && !is_virt_dev)
|
||||
VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST, 0);
|
||||
if (clear_tpm_owner_request) {
|
||||
VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST, 0);
|
||||
VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_DONE, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the nvram state was lost, try to restore the bits we care about
|
||||
* from the backup in the TPM. It's okay if we can't, though.
|
||||
* Note: None of the bits that we back up should have been referenced
|
||||
* before this point. Otherwise, they'll just be overwritten here.
|
||||
* All the other bits will be unchanged from whatever has happened to
|
||||
* them since VbNvSetup() reinitialized the VbNvContext.
|
||||
*/
|
||||
if (lost_nvram)
|
||||
RestoreNvFromBackup(&vnc);
|
||||
|
||||
/* Allow BIOS to load arbitrary option ROMs? */
|
||||
if (gbb.flags & GBB_FLAG_LOAD_OPTION_ROMS)
|
||||
iparams->out_flags |= VB_INIT_OUT_ENABLE_OPROM;
|
||||
|
||||
/* Factory may need to boot custom OSes when the dev-switch is on */
|
||||
if (is_dev && (gbb.flags & GBB_FLAG_ENABLE_ALTERNATE_OS))
|
||||
iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS;
|
||||
|
||||
/* Set output flags */
|
||||
if (VBNV_RECOVERY_NOT_REQUESTED != recovery) {
|
||||
/* Requesting recovery mode */
|
||||
iparams->out_flags |= (VB_INIT_OUT_ENABLE_RECOVERY |
|
||||
VB_INIT_OUT_CLEAR_RAM |
|
||||
VB_INIT_OUT_ENABLE_DISPLAY |
|
||||
VB_INIT_OUT_ENABLE_USB_STORAGE);
|
||||
} else if (is_dev) {
|
||||
/* Developer switch is on, so need to support dev mode */
|
||||
iparams->out_flags |= (VB_INIT_OUT_ENABLE_DEVELOPER |
|
||||
VB_INIT_OUT_CLEAR_RAM |
|
||||
VB_INIT_OUT_ENABLE_DISPLAY |
|
||||
VB_INIT_OUT_ENABLE_USB_STORAGE);
|
||||
/* ... which may or may not include custom OSes */
|
||||
VbNvGet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &require_official_os);
|
||||
if (!require_official_os)
|
||||
iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS;
|
||||
|
||||
/*
|
||||
* Dev-mode needs the VGA option ROM to be loaded so it can
|
||||
* display the scary boot screen. If we don't have it, we need
|
||||
* to request it and reboot so it can be loaded.
|
||||
*/
|
||||
if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) &&
|
||||
!(iparams->flags & VB_INIT_FLAG_OPROM_LOADED)) {
|
||||
VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
|
||||
/*
|
||||
* If VbInit() is run before Option ROMs are run it
|
||||
* can still respond to the VbNv flag and does not
|
||||
* need to reboot here.
|
||||
*/
|
||||
if (!(iparams->flags & VB_INIT_FLAG_BEFORE_OPROM_LOAD))
|
||||
retval = VBERROR_VGA_OPROM_MISMATCH;
|
||||
VBDEBUG(("VbInit() needs oprom, doesn't have it\n"));
|
||||
}
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Normal mode, so disable dev_boot_* flags. This ensures they
|
||||
* will be initially disabled if the user later transitions
|
||||
* back into developer mode.
|
||||
*/
|
||||
VbNvSet(&vnc, VBNV_DEV_BOOT_USB, 0);
|
||||
VbNvSet(&vnc, VBNV_DEV_BOOT_LEGACY, 0);
|
||||
VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 0);
|
||||
VbNvSet(&vnc, VBNV_DEV_BOOT_FASTBOOT_FULL_CAP, 0);
|
||||
VbNvSet(&vnc, VBNV_DEV_DEFAULT_BOOT, 0);
|
||||
VbNvSet(&vnc, VBNV_FASTBOOT_UNLOCK_IN_FW, 0);
|
||||
/*
|
||||
* Back up any changes now, so these values can't be forgotten
|
||||
* by draining the battery. We really only care about these
|
||||
* three fields, but it's uncommon for any others to change so
|
||||
* this is an easier test than checking each one.
|
||||
*/
|
||||
if (vnc.regenerate_crc)
|
||||
backup_for_safety = 1;
|
||||
|
||||
/*
|
||||
* If we don't need the VGA option ROM but got it anyway, stop
|
||||
* asking for it and reboot in case there's some vulnerability
|
||||
* in using it.
|
||||
*/
|
||||
if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) &&
|
||||
(iparams->flags & VB_INIT_FLAG_OPROM_LOADED)) {
|
||||
VbNvSet(&vnc, VBNV_OPROM_NEEDED, 0);
|
||||
/*
|
||||
* If VbInit() is run before Option ROMs are run it
|
||||
* can still respond to the VbNv flag and does not
|
||||
* need to reboot here.
|
||||
*/
|
||||
if (!(iparams->flags & VB_INIT_FLAG_BEFORE_OPROM_LOAD))
|
||||
retval = VBERROR_VGA_OPROM_MISMATCH;
|
||||
VBDEBUG(("VbInit() has oprom, doesn't need it\n"));
|
||||
}
|
||||
}
|
||||
|
||||
VbInit_exit:
|
||||
/*
|
||||
* If we successfully backup the NV storage, it will clear the
|
||||
* VBNV_BACKUP_NVRAM_REQUEST field, so we want to do it before
|
||||
* calling VbNvTeardown(). It's okay if we can't backup, though.
|
||||
*/
|
||||
VbNvGet(&vnc, VBNV_BACKUP_NVRAM_REQUEST, &backup_requested);
|
||||
if (backup_requested || backup_for_safety)
|
||||
SaveNvToBackup(&vnc);
|
||||
|
||||
/* Tear down NV storage */
|
||||
VbNvTeardown(&vnc);
|
||||
if (vnc.raw_changed)
|
||||
VbExNvStorageWrite(vnc.raw);
|
||||
|
||||
VBDEBUG(("VbInit() output flags 0x%x\n", iparams->out_flags));
|
||||
|
||||
shared->timer_vb_init_exit = VbExGetTimer();
|
||||
|
||||
VBDEBUG(("VbInit() returning 0x%x\n", retval));
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -1,368 +0,0 @@
|
||||
/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* High-level firmware API for loading and verifying rewritable firmware.
|
||||
* (Firmware portion)
|
||||
*/
|
||||
|
||||
#include "sysincludes.h"
|
||||
#include "2sysincludes.h"
|
||||
|
||||
#include "2common.h"
|
||||
#include "2sha.h"
|
||||
#include "region.h"
|
||||
#include "gbb_access.h"
|
||||
#include "gbb_header.h"
|
||||
#include "load_firmware_fw.h"
|
||||
#include "utility.h"
|
||||
#include "vboot_api.h"
|
||||
#include "vboot_common.h"
|
||||
#include "vboot_nvstorage.h"
|
||||
|
||||
/*
|
||||
* Static variables for UpdateFirmwareBodyHash(). It's less than optimal to
|
||||
* have static variables in a library, but in UEFI the caller is deep inside a
|
||||
* different firmware stack and doesn't have a good way to pass the params
|
||||
* struct back to us.
|
||||
*/
|
||||
typedef struct VbLoadFirmwareInternal {
|
||||
struct vb2_digest_context body_digest_context;
|
||||
uint32_t body_size_accum;
|
||||
} VbLoadFirmwareInternal;
|
||||
|
||||
void VbUpdateFirmwareBodyHash(VbCommonParams *cparams, uint8_t *data,
|
||||
uint32_t size)
|
||||
{
|
||||
VbLoadFirmwareInternal *lfi =
|
||||
(VbLoadFirmwareInternal*)cparams->vboot_context;
|
||||
|
||||
vb2_digest_extend(&lfi->body_digest_context, data, size);
|
||||
lfi->body_size_accum += size;
|
||||
}
|
||||
|
||||
int LoadFirmware(VbCommonParams *cparams, VbSelectFirmwareParams *fparams,
|
||||
VbNvContext *vnc)
|
||||
{
|
||||
VbSharedDataHeader *shared =
|
||||
(VbSharedDataHeader *)cparams->shared_data_blob;
|
||||
GoogleBinaryBlockHeader *gbb = cparams->gbb;
|
||||
VbPublicKey *root_key = NULL;
|
||||
VbLoadFirmwareInternal *lfi;
|
||||
|
||||
uint32_t try_b_count;
|
||||
uint32_t lowest_version = 0xFFFFFFFF;
|
||||
int good_index = -1;
|
||||
int is_dev;
|
||||
int index;
|
||||
int i;
|
||||
|
||||
int retval = VBERROR_UNKNOWN;
|
||||
int recovery = VBNV_RECOVERY_RO_UNSPECIFIED;
|
||||
|
||||
/* Clear output params in case we fail */
|
||||
shared->firmware_index = 0xFF;
|
||||
|
||||
VBDEBUG(("LoadFirmware started...\n"));
|
||||
|
||||
/* Must have a root key from the GBB */
|
||||
retval = VbGbbReadRootKey(cparams, &root_key);
|
||||
if (retval) {
|
||||
VBDEBUG(("No GBB\n"));
|
||||
retval = VBERROR_INVALID_GBB;
|
||||
goto LoadFirmwareExit;
|
||||
}
|
||||
|
||||
/* Parse flags */
|
||||
is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0);
|
||||
if (is_dev)
|
||||
shared->flags |= VBSD_LF_DEV_SWITCH_ON;
|
||||
|
||||
/* Read try-b count and decrement if necessary */
|
||||
VbNvGet(vnc, VBNV_TRY_B_COUNT, &try_b_count);
|
||||
if (0 != try_b_count) {
|
||||
if (!(shared->flags & VBSD_NOFAIL_BOOT))
|
||||
VbNvSet(vnc, VBNV_TRY_B_COUNT, try_b_count - 1);
|
||||
shared->flags |= VBSD_FWB_TRIED;
|
||||
}
|
||||
|
||||
/* Allocate our internal data */
|
||||
lfi = (VbLoadFirmwareInternal *)
|
||||
VbExMalloc(sizeof(VbLoadFirmwareInternal));
|
||||
cparams->vboot_context = lfi;
|
||||
|
||||
/* Loop over indices */
|
||||
for (i = 0; i < 2; i++) {
|
||||
VbKeyBlockHeader *key_block;
|
||||
uint32_t vblock_size;
|
||||
VbFirmwarePreambleHeader *preamble;
|
||||
RSAPublicKey *data_key;
|
||||
uint64_t key_version;
|
||||
uint32_t combined_version;
|
||||
uint8_t *check_result;
|
||||
|
||||
/* If try B count is non-zero try firmware B first */
|
||||
index = (try_b_count ? 1 - i : i);
|
||||
if (0 == index) {
|
||||
key_block = (VbKeyBlockHeader *)
|
||||
fparams->verification_block_A;
|
||||
vblock_size = fparams->verification_size_A;
|
||||
check_result = &shared->check_fw_a_result;
|
||||
} else {
|
||||
key_block = (VbKeyBlockHeader *)
|
||||
fparams->verification_block_B;
|
||||
vblock_size = fparams->verification_size_B;
|
||||
check_result = &shared->check_fw_b_result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the key block flags against the current boot mode. Do
|
||||
* this before verifying the key block, since flags are faster
|
||||
* to check than the RSA signature.
|
||||
*/
|
||||
if (!(key_block->key_block_flags &
|
||||
(is_dev ? KEY_BLOCK_FLAG_DEVELOPER_1 :
|
||||
KEY_BLOCK_FLAG_DEVELOPER_0))) {
|
||||
VBDEBUG(("Developer flag mismatch.\n"));
|
||||
*check_result = VBSD_LF_CHECK_DEV_MISMATCH;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* RW firmware never runs in recovery mode. */
|
||||
if (!(key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)) {
|
||||
VBDEBUG(("Recovery flag mismatch.\n"));
|
||||
*check_result = VBSD_LF_CHECK_REC_MISMATCH;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Verify the key block */
|
||||
if ((0 != KeyBlockVerify(key_block, vblock_size,
|
||||
root_key, 0))) {
|
||||
VBDEBUG(("Key block verification failed.\n"));
|
||||
*check_result = VBSD_LF_CHECK_VERIFY_KEYBLOCK;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check for rollback of key version. */
|
||||
key_version = key_block->data_key.key_version;
|
||||
if (!(gbb->flags & GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK)) {
|
||||
if (key_version < (shared->fw_version_tpm >> 16)) {
|
||||
VBDEBUG(("Key rollback detected.\n"));
|
||||
*check_result = VBSD_LF_CHECK_KEY_ROLLBACK;
|
||||
continue;
|
||||
}
|
||||
if (key_version > 0xFFFF) {
|
||||
/*
|
||||
* Key version is stored in 16 bits in the TPM,
|
||||
* so key versions greater than 0xFFFF can't be
|
||||
* stored properly.
|
||||
*/
|
||||
VBDEBUG(("Key version > 0xFFFF.\n"));
|
||||
*check_result = VBSD_LF_CHECK_KEY_ROLLBACK;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get key for preamble/data verification from the key block. */
|
||||
data_key = PublicKeyToRSA(&key_block->data_key);
|
||||
if (!data_key) {
|
||||
VBDEBUG(("Unable to parse data key.\n"));
|
||||
*check_result = VBSD_LF_CHECK_DATA_KEY_PARSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Verify the preamble, which follows the key block. */
|
||||
preamble = (VbFirmwarePreambleHeader *)
|
||||
((uint8_t *)key_block + key_block->key_block_size);
|
||||
if ((0 != VerifyFirmwarePreamble(
|
||||
preamble,
|
||||
vblock_size - key_block->key_block_size,
|
||||
data_key))) {
|
||||
VBDEBUG(("Preamble verfication failed.\n"));
|
||||
*check_result = VBSD_LF_CHECK_VERIFY_PREAMBLE;
|
||||
RSAPublicKeyFree(data_key);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check for rollback of firmware version. */
|
||||
combined_version = (uint32_t)((key_version << 16) |
|
||||
(preamble->firmware_version & 0xFFFF));
|
||||
if (combined_version < shared->fw_version_tpm &&
|
||||
!(gbb->flags & GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK)) {
|
||||
VBDEBUG(("Firmware version rollback detected.\n"));
|
||||
*check_result = VBSD_LF_CHECK_FW_ROLLBACK;
|
||||
RSAPublicKeyFree(data_key);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Header for this firmware is valid */
|
||||
*check_result = VBSD_LF_CHECK_HEADER_VALID;
|
||||
|
||||
/* Check for lowest key version from a valid header. */
|
||||
if (lowest_version > combined_version)
|
||||
lowest_version = combined_version;
|
||||
|
||||
/*
|
||||
* If we already have good firmware, no need to read another
|
||||
* one; we only needed to look at the versions to check for
|
||||
* rollback.
|
||||
*/
|
||||
if (-1 != good_index) {
|
||||
RSAPublicKeyFree(data_key);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Handle preamble flag for using the RO normal/dev code path */
|
||||
VBDEBUG(("Preamble flags %#x\n", VbGetFirmwarePreambleFlags(preamble)));
|
||||
if (VbGetFirmwarePreambleFlags(preamble) &
|
||||
VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
|
||||
|
||||
/* Fail if calling firmware doesn't support RO normal */
|
||||
if (!(shared->flags & VBSD_BOOT_RO_NORMAL_SUPPORT)) {
|
||||
VBDEBUG(("No RO normal support.\n"));
|
||||
*check_result = VBSD_LF_CHECK_NO_RO_NORMAL;
|
||||
RSAPublicKeyFree(data_key);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Use the RO normal code path */
|
||||
shared->flags |= VBSD_LF_USE_RO_NORMAL;
|
||||
|
||||
} else {
|
||||
VbError_t rv;
|
||||
|
||||
/* Read the firmware data */
|
||||
vb2_digest_init(&lfi->body_digest_context,
|
||||
vb2_crypto_to_hash(data_key->algorithm));
|
||||
lfi->body_size_accum = 0;
|
||||
rv = VbExHashFirmwareBody(
|
||||
cparams,
|
||||
(index ? VB_SELECT_FIRMWARE_B :
|
||||
VB_SELECT_FIRMWARE_A));
|
||||
if (VBERROR_SUCCESS != rv) {
|
||||
VBDEBUG(("VbExHashFirmwareBody() failed for "
|
||||
"index %d\n", index));
|
||||
*check_result = VBSD_LF_CHECK_GET_FW_BODY;
|
||||
RSAPublicKeyFree(data_key);
|
||||
continue;
|
||||
}
|
||||
if (lfi->body_size_accum !=
|
||||
preamble->body_signature.data_size) {
|
||||
VBDEBUG(("Hashed %d bytes but expected %d\n",
|
||||
(int)lfi->body_size_accum,
|
||||
(int)preamble->body_signature.data_size));
|
||||
*check_result = VBSD_LF_CHECK_HASH_WRONG_SIZE;
|
||||
RSAPublicKeyFree(data_key);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Verify firmware data */
|
||||
uint8_t body_digest[VB2_MAX_DIGEST_SIZE];
|
||||
vb2_digest_finalize(&lfi->body_digest_context,
|
||||
body_digest, sizeof(body_digest));
|
||||
if (0 != VerifyDigest(body_digest,
|
||||
&preamble->body_signature,
|
||||
data_key)) {
|
||||
VBDEBUG(("FW body verification failed.\n"));
|
||||
*check_result = VBSD_LF_CHECK_VERIFY_BODY;
|
||||
RSAPublicKeyFree(data_key);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Done with the data key, so can free it now */
|
||||
RSAPublicKeyFree(data_key);
|
||||
|
||||
/* If we're still here, the firmware is valid. */
|
||||
VBDEBUG(("Firmware %d is valid.\n", index));
|
||||
*check_result = VBSD_LF_CHECK_VALID;
|
||||
if (-1 == good_index) {
|
||||
/* Save the key we actually used */
|
||||
if (0 != VbSharedDataSetKernelKey(
|
||||
shared, &preamble->kernel_subkey)) {
|
||||
/*
|
||||
* The firmware signature was good, but the
|
||||
* public key was bigger that the caller can
|
||||
* handle.
|
||||
*/
|
||||
VBDEBUG(("Unable to save kernel subkey.\n"));
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the good index, now that we're sure we can
|
||||
* actually use this firmware. That's the one we'll
|
||||
* boot.
|
||||
*/
|
||||
good_index = index;
|
||||
shared->firmware_index = (uint8_t)index;
|
||||
shared->fw_keyblock_flags = key_block->key_block_flags;
|
||||
|
||||
/*
|
||||
* If the good firmware's key version is the same as
|
||||
* the tpm, then the TPM doesn't need updating; we can
|
||||
* stop now. Otherwise, we'll check all the other
|
||||
* headers to see if they contain a newer key.
|
||||
*/
|
||||
if (combined_version == shared->fw_version_tpm)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free internal data */
|
||||
VbExFree(lfi);
|
||||
cparams->vboot_context = NULL;
|
||||
|
||||
/* Handle finding good firmware */
|
||||
if (good_index >= 0) {
|
||||
|
||||
/* Save versions we found */
|
||||
shared->fw_version_lowest = lowest_version;
|
||||
if (lowest_version > shared->fw_version_tpm)
|
||||
shared->fw_version_tpm = lowest_version;
|
||||
|
||||
/* Success */
|
||||
VBDEBUG(("Will boot firmware index %d\n",
|
||||
(int)shared->firmware_index));
|
||||
retval = VBERROR_SUCCESS;
|
||||
|
||||
} else {
|
||||
uint8_t a = shared->check_fw_a_result;
|
||||
uint8_t b = shared->check_fw_b_result;
|
||||
uint8_t best_check;
|
||||
|
||||
/* No good firmware, so go to recovery mode. */
|
||||
VBDEBUG(("Alas, no good firmware.\n"));
|
||||
recovery = VBNV_RECOVERY_RO_INVALID_RW;
|
||||
retval = VBERROR_LOAD_FIRMWARE;
|
||||
|
||||
/*
|
||||
* If the best check result fits in the range of recovery
|
||||
* reasons, provide more detail on how far we got in
|
||||
* validation.
|
||||
*/
|
||||
best_check = (a > b ? a : b) +
|
||||
VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN;
|
||||
if (best_check >= VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN &&
|
||||
best_check <= VBNV_RECOVERY_RO_INVALID_RW_CHECK_MAX)
|
||||
recovery = best_check;
|
||||
}
|
||||
|
||||
LoadFirmwareExit:
|
||||
VbExFree(root_key);
|
||||
|
||||
/* Store recovery request, if any */
|
||||
VbNvSet(vnc, VBNV_RECOVERY_REQUEST, VBERROR_SUCCESS != retval ?
|
||||
recovery : VBNV_RECOVERY_NOT_REQUESTED);
|
||||
/* If the system does not support RO_NORMAL and LoadFirmware()
|
||||
* encountered an error, update the shared recovery reason if
|
||||
* recovery was not previously requested. */
|
||||
if (!(shared->flags & VBSD_BOOT_RO_NORMAL_SUPPORT) &&
|
||||
VBNV_RECOVERY_NOT_REQUESTED == shared->recovery_reason &&
|
||||
VBERROR_SUCCESS != retval) {
|
||||
VBDEBUG(("RO normal but we got an error.\n"));
|
||||
shared->recovery_reason = recovery;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/* Non-volatile storage routines.
|
||||
*/
|
||||
#include "sysincludes.h"
|
||||
|
||||
#include "crc8.h"
|
||||
#include "utility.h"
|
||||
#include "vboot_common.h"
|
||||
#include "vboot_nvstorage.h"
|
||||
#include "rollback_index.h"
|
||||
|
||||
/* These are the fields of the nvram that we want to back up. */
|
||||
static const VbNvParam backup_params[] = {
|
||||
VBNV_KERNEL_FIELD,
|
||||
VBNV_LOCALIZATION_INDEX,
|
||||
VBNV_DEV_BOOT_USB,
|
||||
VBNV_DEV_BOOT_LEGACY,
|
||||
VBNV_DEV_BOOT_SIGNED_ONLY,
|
||||
VBNV_DEV_BOOT_FASTBOOT_FULL_CAP,
|
||||
VBNV_DEV_DEFAULT_BOOT,
|
||||
VBNV_FASTBOOT_UNLOCK_IN_FW,
|
||||
};
|
||||
|
||||
/* We can't back things up if there isn't enough storage. */
|
||||
BUILD_ASSERT(VBNV_BLOCK_SIZE <= BACKUP_NV_SIZE);
|
||||
|
||||
int RestoreNvFromBackup(VbNvContext *vnc)
|
||||
{
|
||||
VbNvContext bvnc;
|
||||
uint32_t value;
|
||||
int i;
|
||||
|
||||
VBDEBUG(("TPM: %s()\n", __func__));
|
||||
|
||||
if (TPM_SUCCESS != RollbackBackupRead(bvnc.raw))
|
||||
return 1;
|
||||
|
||||
VbNvSetup(&bvnc);
|
||||
if (bvnc.regenerate_crc) {
|
||||
VBDEBUG(("TPM: Oops, backup is no good.\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(backup_params); i++) {
|
||||
VbNvGet(&bvnc, backup_params[i], &value);
|
||||
VbNvSet(vnc, backup_params[i], value);
|
||||
}
|
||||
|
||||
/* VbNvTeardown(&bvnc); is not needed. We're done with it. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SaveNvToBackup(VbNvContext *vnc)
|
||||
{
|
||||
VbNvContext bvnc;
|
||||
uint32_t value;
|
||||
int i;
|
||||
|
||||
VBDEBUG(("TPM: %s()\n", __func__));
|
||||
|
||||
/* Read it first. No point in writing the same data. */
|
||||
if (TPM_SUCCESS != RollbackBackupRead(bvnc.raw))
|
||||
return 1;
|
||||
|
||||
VbNvSetup(&bvnc);
|
||||
VBDEBUG(("TPM: existing backup is %s\n",
|
||||
bvnc.regenerate_crc ? "bad" : "good"));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(backup_params); i++) {
|
||||
VbNvGet(vnc, backup_params[i], &value);
|
||||
VbNvSet(&bvnc, backup_params[i], value);
|
||||
}
|
||||
|
||||
VbNvTeardown(&bvnc);
|
||||
|
||||
if (!bvnc.raw_changed) {
|
||||
VBDEBUG(("TPM: Nothing's changed, not writing backup\n"));
|
||||
/* Clear the request flag, since we're happy. */
|
||||
VbNvSet(vnc, VBNV_BACKUP_NVRAM_REQUEST, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (TPM_SUCCESS == RollbackBackupWrite(bvnc.raw)) {
|
||||
/* Clear the request flag if we wrote successfully too */
|
||||
VbNvSet(vnc, VBNV_BACKUP_NVRAM_REQUEST, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
VBDEBUG(("TPM: Sorry, couldn't write backup.\n"));
|
||||
return 1;
|
||||
}
|
||||
Reference in New Issue
Block a user