ec_sync: Run EFS2 in romstage

EFS2 allows EC RO to enable PD for special cases. When doing so, it sets
NO_BOOT flag to avoid booting the OS. AP needs to get NO_BOOT flag from
Cr50 and enforce that.

This patch makes verstage get a boot mode and a mirrored hash stored
in kernel secdata from Cr50.

This patch also makes romstage write an expected EC hash (a.k.a. Hexp) to
Cr50 (if there is an update).

BUG=b:147298634, chromium:1045217, b:148259137
BRANCH=none
TEST=Verify software sync succeeds on Puff.

Signed-off-by: dnojiri <dnojiri@chromium.org>
Change-Id: I1f387b6e920205b9cc4c8536561f2a279c36413d
Reviewed-on: https://review.coreboot.org/c/coreboot/+/40389
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
dnojiri 2020-04-03 10:56:43 -07:00 committed by Julius Werner
parent 622c6b84ab
commit dff56a056c
6 changed files with 109 additions and 17 deletions

View File

@ -71,6 +71,12 @@ uint32_t antirollback_read_space_firmware(struct vb2_context *ctx);
*/
uint32_t antirollback_write_space_firmware(struct vb2_context *ctx);
/**
* Read and write kernel space in TPM.
*/
uint32_t antirollback_read_space_kernel(struct vb2_context *ctx);
uint32_t antirollback_write_space_kernel(struct vb2_context *ctx);
/**
* Lock must be called.
*/

View File

@ -50,7 +50,7 @@ void vboot_sync_ec(void)
ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED;
retval = vb2api_ec_sync(ctx);
vboot_save_nvdata_only(ctx);
vboot_save_data(ctx);
switch (retval) {
case VB2_SUCCESS:

View File

@ -53,6 +53,17 @@ vb2_error_t antirollback_write_space_firmware(struct vb2_context *ctx)
return VB2_SUCCESS;
}
vb2_error_t antirollback_read_space_kernel(struct vb2_context *ctx)
{
vb2api_secdata_kernel_create(ctx);
return VB2_SUCCESS;
}
vb2_error_t antirollback_write_space_kernel(struct vb2_context *ctx)
{
return VB2_SUCCESS;
}
vb2_error_t antirollback_lock_space_firmware(void)
{
return VB2_SUCCESS;

View File

@ -80,6 +80,22 @@ static uint32_t read_space_firmware(struct vb2_context *ctx)
return TPM_E_CORRUPTED_STATE;
}
uint32_t antirollback_read_space_kernel(struct vb2_context *ctx)
{
uint8_t size = VB2_SECDATA_KERNEL_MIN_SIZE;
RETURN_ON_FAILURE(tlcl_read(KERNEL_NV_INDEX, ctx->secdata_kernel,
size));
if (vb2api_secdata_kernel_check(ctx, &size)
== VB2_ERROR_SECDATA_KERNEL_INCOMPLETE)
/* Re-read. vboot will run the check and handle errors. */
RETURN_ON_FAILURE(tlcl_read(KERNEL_NV_INDEX,
ctx->secdata_kernel, size));
return TPM_SUCCESS;
}
static uint32_t read_space_rec_hash(uint8_t *data)
{
RETURN_ON_FAILURE(tlcl_read(REC_HASH_NV_INDEX, data,
@ -440,6 +456,15 @@ uint32_t antirollback_write_space_firmware(struct vb2_context *ctx)
VB2_SECDATA_FIRMWARE_SIZE);
}
uint32_t antirollback_write_space_kernel(struct vb2_context *ctx)
{
/* Learn the expected size. */
uint8_t size = VB2_SECDATA_KERNEL_MIN_SIZE;
vb2api_secdata_kernel_check(ctx, &size);
return write_secdata(KERNEL_NV_INDEX, ctx->secdata_kernel, size);
}
uint32_t antirollback_read_space_rec_hash(uint8_t *data, uint32_t size)
{
if (size != REC_HASH_NV_SIZE) {

View File

@ -61,7 +61,6 @@ static inline void vboot_run_logic(void) {}
static inline int vboot_locate_cbfs(struct region_device *rdev) { return -1; }
#endif
void vboot_save_nvdata_only(struct vb2_context *ctx);
void vboot_save_data(struct vb2_context *ctx);
/*

View File

@ -7,6 +7,7 @@
#include <cbmem.h>
#include <fmap.h>
#include <security/tpm/tspi/crtm.h>
#include <security/tpm/tss/vendor/cr50/cr50.h>
#include <security/vboot/misc.h>
#include <security/vboot/vbnv.h>
#include <security/vboot/tpm_common.h>
@ -207,10 +208,21 @@ static vb2_error_t hash_body(struct vb2_context *ctx,
return VB2_SUCCESS;
}
void vboot_save_nvdata_only(struct vb2_context *ctx)
void vboot_save_data(struct vb2_context *ctx)
{
assert(!(ctx->flags & (VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED |
VB2_CONTEXT_SECDATA_KERNEL_CHANGED)));
if (ctx->flags & VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED &&
(CONFIG(VBOOT_MOCK_SECDATA) || tlcl_lib_init() == VB2_SUCCESS)) {
printk(BIOS_INFO, "Saving secdata firmware\n");
antirollback_write_space_firmware(ctx);
ctx->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED;
}
if (ctx->flags & VB2_CONTEXT_SECDATA_KERNEL_CHANGED &&
(CONFIG(VBOOT_MOCK_SECDATA) || tlcl_lib_init() == VB2_SUCCESS)) {
printk(BIOS_INFO, "Saving secdata kernel\n");
antirollback_write_space_kernel(ctx);
ctx->flags &= ~VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
}
if (ctx->flags & VB2_CONTEXT_NVDATA_CHANGED) {
printk(BIOS_INFO, "Saving nvdata\n");
@ -219,23 +231,57 @@ void vboot_save_nvdata_only(struct vb2_context *ctx)
}
}
void vboot_save_data(struct vb2_context *ctx)
{
if (ctx->flags & VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED) {
printk(BIOS_INFO, "Saving secdata\n");
antirollback_write_space_firmware(ctx);
ctx->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED;
}
vboot_save_nvdata_only(ctx);
}
static uint32_t extend_pcrs(struct vb2_context *ctx)
{
return vboot_extend_pcr(ctx, 0, BOOT_MODE_PCR) ||
vboot_extend_pcr(ctx, 1, HWID_DIGEST_PCR);
}
#define EC_EFS_BOOT_MODE_NORMAL 0x00
#define EC_EFS_BOOT_MODE_NO_BOOT 0x01
static const char *get_boot_mode_string(uint8_t boot_mode)
{
if (boot_mode == EC_EFS_BOOT_MODE_NORMAL)
return "NORMAL";
else if (boot_mode == EC_EFS_BOOT_MODE_NO_BOOT)
return "NO_BOOT";
else
return "UNDEFINED";
}
static void check_boot_mode(struct vb2_context *ctx)
{
uint8_t boot_mode;
int rv;
rv = tlcl_cr50_get_boot_mode(&boot_mode);
switch (rv) {
case TPM_E_NO_SUCH_COMMAND:
printk(BIOS_WARNING, "Cr50 does not support GET_BOOT_MODE.\n");
/* Proceed to legacy boot model. */
return;
case TPM_SUCCESS:
break;
default:
printk(BIOS_ERR,
"Communication error in getting Cr50 boot mode.\n");
if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE)
/* Continue to boot in recovery mode */
return;
vb2api_fail(ctx, VB2_RECOVERY_CR50_BOOT_MODE, rv);
vboot_save_data(ctx);
vboot_reboot();
return;
}
printk(BIOS_INFO, "Cr50 says boot_mode is %s(0x%02x).\n",
get_boot_mode_string(boot_mode), boot_mode);
if (boot_mode == EC_EFS_BOOT_MODE_NO_BOOT)
ctx->flags |= VB2_CONTEXT_NO_BOOT;
}
/**
* Verify and select the firmware in the RW image
*
@ -268,8 +314,10 @@ void verstage_main(void)
* check the return value here because vb2api_fw_phase1 will catch
* invalid secdata and tell us what to do (=reboot). */
timestamp_add_now(TS_START_TPMINIT);
if (vboot_setup_tpm(ctx) == TPM_SUCCESS)
if (vboot_setup_tpm(ctx) == TPM_SUCCESS) {
antirollback_read_space_firmware(ctx);
antirollback_read_space_kernel(ctx);
}
timestamp_add_now(TS_END_TPMINIT);
if (get_recovery_mode_switch()) {
@ -359,6 +407,9 @@ void verstage_main(void)
timestamp_add_now(TS_END_TPMPCR);
}
if (CONFIG(TPM_CR50))
check_boot_mode(ctx);
/* Lock TPM */
timestamp_add_now(TS_START_TPMLOCK);