diff options
author | dnojiri <dnojiri@chromium.org> | 2020-04-03 10:56:43 -0700 |
---|---|---|
committer | Julius Werner <jwerner@chromium.org> | 2020-04-17 22:01:48 +0000 |
commit | dff56a056c7dadf0d970cfe29f0bc9c1fec69e82 (patch) | |
tree | f45288b8377774613b0a3deffe689dcd64977af7 | |
parent | 622c6b84ab029a366dd09740a24d36ae9fad697f (diff) |
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.h | 6 | ||||
-rw-r--r-- | src/security/vboot/ec_sync.c | 2 | ||||
-rw-r--r-- | src/security/vboot/secdata_mock.c | 11 | ||||
-rw-r--r-- | src/security/vboot/secdata_tpm.c | 25 | ||||
-rw-r--r-- | src/security/vboot/vboot_common.h | 1 | ||||
-rw-r--r-- | src/security/vboot/vboot_logic.c | 79 |
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); |