summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordnojiri <dnojiri@chromium.org>2020-04-03 10:56:43 -0700
committerJulius Werner <jwerner@chromium.org>2020-04-17 22:01:48 +0000
commitdff56a056c7dadf0d970cfe29f0bc9c1fec69e82 (patch)
treef45288b8377774613b0a3deffe689dcd64977af7
parent622c6b84ab029a366dd09740a24d36ae9fad697f (diff)
downloadcoreboot-dff56a056c7dadf0d970cfe29f0bc9c1fec69e82.tar.xz
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>
-rw-r--r--src/security/vboot/antirollback.h6
-rw-r--r--src/security/vboot/ec_sync.c2
-rw-r--r--src/security/vboot/secdata_mock.c11
-rw-r--r--src/security/vboot/secdata_tpm.c25
-rw-r--r--src/security/vboot/vboot_common.h1
-rw-r--r--src/security/vboot/vboot_logic.c79
6 files changed, 108 insertions, 16 deletions
diff --git a/src/security/vboot/antirollback.h b/src/security/vboot/antirollback.h
index 5af923600d..6bc020d208 100644
--- a/src/security/vboot/antirollback.h
+++ b/src/security/vboot/antirollback.h
@@ -72,6 +72,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.
*/
uint32_t antirollback_lock_space_firmware(void);
diff --git a/src/security/vboot/ec_sync.c b/src/security/vboot/ec_sync.c
index 3a177b16e8..580e6c6b8d 100644
--- a/src/security/vboot/ec_sync.c
+++ b/src/security/vboot/ec_sync.c
@@ -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:
diff --git a/src/security/vboot/secdata_mock.c b/src/security/vboot/secdata_mock.c
index a4957f9575..edb6739653 100644
--- a/src/security/vboot/secdata_mock.c
+++ b/src/security/vboot/secdata_mock.c
@@ -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;
diff --git a/src/security/vboot/secdata_tpm.c b/src/security/vboot/secdata_tpm.c
index 0ae956276c..b60a1bb315 100644
--- a/src/security/vboot/secdata_tpm.c
+++ b/src/security/vboot/secdata_tpm.c
@@ -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) {
diff --git a/src/security/vboot/vboot_common.h b/src/security/vboot/vboot_common.h
index 50995e6c04..f25ee46b6f 100644
--- a/src/security/vboot/vboot_common.h
+++ b/src/security/vboot/vboot_common.h
@@ -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);
/*
diff --git a/src/security/vboot/vboot_logic.c b/src/security/vboot/vboot_logic.c
index 9e9e82ac6b..8e82e40bf0 100644
--- a/src/security/vboot/vboot_logic.c
+++ b/src/security/vboot/vboot_logic.c
@@ -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,21 +231,55 @@ void vboot_save_nvdata_only(struct vb2_context *ctx)
}
}
-void vboot_save_data(struct vb2_context *ctx)
+static uint32_t extend_pcrs(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;
- }
+ return vboot_extend_pcr(ctx, 0, BOOT_MODE_PCR) ||
+ vboot_extend_pcr(ctx, 1, HWID_DIGEST_PCR);
+}
- vboot_save_nvdata_only(ctx);
+#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 uint32_t extend_pcrs(struct vb2_context *ctx)
+static void check_boot_mode(struct vb2_context *ctx)
{
- return vboot_extend_pcr(ctx, 0, BOOT_MODE_PCR) ||
- vboot_extend_pcr(ctx, 1, HWID_DIGEST_PCR);
+ 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;
}
/**
@@ -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);