diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/2lib/2api.c | 21 | ||||
-rw-r--r-- | firmware/2lib/2nvstorage.c | 7 | ||||
-rw-r--r-- | firmware/2lib/include/2api.h | 16 | ||||
-rw-r--r-- | firmware/2lib/include/2nvstorage.h | 2 | ||||
-rw-r--r-- | firmware/2lib/include/2nvstorage_fields.h | 3 | ||||
-rw-r--r-- | firmware/2lib/include/2return_codes.h | 3 | ||||
-rw-r--r-- | firmware/include/vboot_nvstorage.h | 2 | ||||
-rw-r--r-- | firmware/lib/vboot_nvstorage.c | 12 |
8 files changed, 63 insertions, 3 deletions
diff --git a/firmware/2lib/2api.c b/firmware/2lib/2api.c index 70cb8a30..a7b41d2b 100644 --- a/firmware/2lib/2api.c +++ b/firmware/2lib/2api.c @@ -44,6 +44,27 @@ int vb2api_fw_phase1(struct vb2_context *ctx) /* Initialize NV context */ vb2_nv_init(ctx); + /* + * Handle caller-requested reboot due to secdata. Do this before we + * even look at secdata. If we fail because of a reboot loop we'll be + * the first failure so will get to set the recovery reason. + */ + if (!(ctx->flags & VB2_CONTEXT_SECDATA_WANTS_REBOOT)) { + /* No reboot requested */ + vb2_nv_set(ctx, VB2_NV_TPM_REQUESTED_REBOOT, 0); + } else if (vb2_nv_get(ctx, VB2_NV_TPM_REQUESTED_REBOOT)) { + /* + * Reboot requested... again. Fool me once, shame on you. + * Fool me twice, shame on me. Fail into recovery to avoid + * a reboot loop. + */ + vb2_fail(ctx, VB2_RECOVERY_RO_TPM_REBOOT, 0); + } else { + /* Reboot requested for the first time */ + vb2_nv_set(ctx, VB2_NV_TPM_REQUESTED_REBOOT, 1); + return VB2_ERROR_API_PHASE1_SECDATA_REBOOT; + } + /* Initialize secure data */ rv = vb2_secdata_init(ctx); if (rv) diff --git a/firmware/2lib/2nvstorage.c b/firmware/2lib/2nvstorage.c index 66a2202f..55f1d0dd 100644 --- a/firmware/2lib/2nvstorage.c +++ b/firmware/2lib/2nvstorage.c @@ -154,6 +154,9 @@ uint32_t vb2_nv_get(struct vb2_context *ctx, enum vb2_nv_param param) case VB2_NV_CLEAR_TPM_OWNER_DONE: return GETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_DONE); + case VB2_NV_TPM_REQUESTED_REBOOT: + return GETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_REBOOTED); + case VB2_NV_REQ_WIPEOUT: return GETBIT(VB2_NV_OFFS_HEADER , VB2_NV_HEADER_WIPEOUT); @@ -309,6 +312,10 @@ void vb2_nv_set(struct vb2_context *ctx, SETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_DONE); break; + case VB2_NV_TPM_REQUESTED_REBOOT: + SETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_REBOOTED); + break; + case VB2_NV_REQ_WIPEOUT: SETBIT(VB2_NV_OFFS_HEADER , VB2_NV_HEADER_WIPEOUT); break; diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h index 95af636d..56d18d69 100644 --- a/firmware/2lib/include/2api.h +++ b/firmware/2lib/include/2api.h @@ -120,6 +120,15 @@ enum vb2_context_flags { /* Boot optimistically: don't touch failure counters */ VB2_CONTEXT_NOFAIL_BOOT = (1 << 12), + + /* + * Secdata is not ready this boot, but should be ready next boot. It + * would like to reboot. The decision whether to reboot or not must be + * deferred until vboot, because rebooting all the time before then + * could cause a device with malfunctioning secdata to get stuck in an + * unrecoverable crash loop. + */ + VB2_CONTEXT_SECDATA_WANTS_REBOOT = (1 << 13), }; /* @@ -411,8 +420,11 @@ void vb2api_fail(struct vb2_context *ctx, uint8_t reason, uint8_t subcode); /** * Firmware selection, phase 1. * - * On error, the calling firmware should jump directly to recovery-mode - * firmware without rebooting. + * If the returned error is VB2_ERROR_API_PHASE1_RECOVERY, the calling firmware + * should jump directly to recovery-mode firmware without rebooting. + * + * For other errors, the calling firmware should check for updates to secdata + * and/or nvdata, then reboot. * * @param ctx Vboot context * @return VB2_SUCCESS, or error code on error. diff --git a/firmware/2lib/include/2nvstorage.h b/firmware/2lib/include/2nvstorage.h index 0a533e3e..bfe9a3a3 100644 --- a/firmware/2lib/include/2nvstorage.h +++ b/firmware/2lib/include/2nvstorage.h @@ -71,6 +71,8 @@ enum vb2_nv_param { VB2_NV_CLEAR_TPM_OWNER_REQUEST, /* Flag that TPM owner was cleared on request. */ VB2_NV_CLEAR_TPM_OWNER_DONE, + /* TPM requested a reboot already. */ + VB2_NV_TPM_REQUESTED_REBOOT, /* More details on recovery reason */ VB2_NV_RECOVERY_SUBCODE, /* Request that NVRAM be backed up at next boot if possible. */ diff --git a/firmware/2lib/include/2nvstorage_fields.h b/firmware/2lib/include/2nvstorage_fields.h index 45d9a7c5..8ae21f87 100644 --- a/firmware/2lib/include/2nvstorage_fields.h +++ b/firmware/2lib/include/2nvstorage_fields.h @@ -63,9 +63,10 @@ enum vb2_nv_offset { #define VB2_NV_DEV_FLAG_LEGACY 0x04 #define VB2_NV_DEV_FLAG_FASTBOOT_FULL_CAP 0x08 -/* Fields in VB2_NV_OFFS_TPM (unused = 0xfc) */ +/* Fields in VB2_NV_OFFS_TPM (unused = 0xf8) */ #define VB2_NV_TPM_CLEAR_OWNER_REQUEST 0x01 #define VB2_NV_TPM_CLEAR_OWNER_DONE 0x02 +#define VB2_NV_TPM_REBOOTED 0x04 /* Fields in VB2_NV_OFFS_MISC (unused = 0xfc) */ #define VB2_NV_MISC_UNLOCK_FASTBOOT 0x01 diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h index 40a4c284..4201b693 100644 --- a/firmware/2lib/include/2return_codes.h +++ b/firmware/2lib/include/2return_codes.h @@ -520,6 +520,9 @@ enum vb2_return_code { /* Bad data key in vb2api_verify_kernel_data() */ VB2_ERROR_API_VERIFY_KDATA_KEY, + /* Phase one passing through secdata's request to reboot */ + VB2_ERROR_API_PHASE1_SECDATA_REBOOT, + /********************************************************************** * Errors which may be generated by implementations of vb2ex functions. * Implementation may also return its own specific errors, which should diff --git a/firmware/include/vboot_nvstorage.h b/firmware/include/vboot_nvstorage.h index 4447ef7f..d3070d93 100644 --- a/firmware/include/vboot_nvstorage.h +++ b/firmware/include/vboot_nvstorage.h @@ -92,6 +92,8 @@ typedef enum VbNvParam { VBNV_CLEAR_TPM_OWNER_REQUEST, /* Flag that TPM owner was cleared on request. */ VBNV_CLEAR_TPM_OWNER_DONE, + /* TPM requested a reboot */ + VBNV_TPM_REQUESTED_REBOOT, /* More details on recovery reason */ VBNV_RECOVERY_SUBCODE, /* Request that NVRAM be backed up at next boot if possible. */ diff --git a/firmware/lib/vboot_nvstorage.c b/firmware/lib/vboot_nvstorage.c index 3b2a725b..6a21bfe8 100644 --- a/firmware/lib/vboot_nvstorage.c +++ b/firmware/lib/vboot_nvstorage.c @@ -46,6 +46,7 @@ #define TPM_FLAGS_OFFSET 5 #define TPM_CLEAR_OWNER_REQUEST 0x01 #define TPM_CLEAR_OWNER_DONE 0x02 +#define TPM_REBOOTED 0x04 #define RECOVERY_SUBCODE_OFFSET 6 @@ -177,6 +178,10 @@ int VbNvGet(VbNvContext *context, VbNvParam param, uint32_t *dest) *dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_DONE ? 1 : 0); return 0; + case VBNV_TPM_REQUESTED_REBOOT: + *dest = (raw[TPM_FLAGS_OFFSET] & TPM_REBOOTED ? 1 : 0); + return 0; + case VBNV_BACKUP_NVRAM_REQUEST: *dest = (raw[BOOT_OFFSET] & BOOT_BACKUP_NVRAM ? 1 : 0); return 0; @@ -347,6 +352,13 @@ int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value) raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_DONE; break; + case VBNV_TPM_REQUESTED_REBOOT: + if (value) + raw[TPM_FLAGS_OFFSET] |= TPM_REBOOTED; + else + raw[TPM_FLAGS_OFFSET] &= ~TPM_REBOOTED; + break; + case VBNV_BACKUP_NVRAM_REQUEST: if (value) raw[BOOT_OFFSET] |= BOOT_BACKUP_NVRAM; |