diff options
author | Joel Kitching <kitching@google.com> | 2020-03-06 14:56:14 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-03-09 08:43:37 +0000 |
commit | cebb4f5912d2a72f86e43d9552edcf881806c6b9 (patch) | |
tree | 8ff44bf028a1a98f81ea62684876e224f5d35985 /firmware | |
parent | 4da0add3b390e9aecd2113375abae874318c7cf4 (diff) | |
download | vboot-cebb4f5912d2a72f86e43d9552edcf881806c6b9.tar.gz |
vboot: create 2kernel.c for kernel-related functions
Create 2kernel.c for kernel-related functions (including
both internal and API-facing).
Relocate functions which are currently in active use from
lib20/api_kernel.c to 2lib/2kernel.c.
Create vb2_kernel_tests.c and move appropriate tests there.
Tests for vb2_normal_boot (previously VbBootNormal) will
be added in a subsequent CL.
BUG=b:124141368, chromium:968464
TEST=make clean && make runtests
BRANCH=none
Change-Id: I153ea318ba238b7b30bf871105388437f63075d1
Signed-off-by: Joel Kitching <kitching@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2091126
Reviewed-by: Joel Kitching <kitching@chromium.org>
Commit-Queue: Joel Kitching <kitching@chromium.org>
Tested-by: Joel Kitching <kitching@chromium.org>
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/2lib/2kernel.c | 193 | ||||
-rw-r--r-- | firmware/2lib/include/2kernel.h | 21 | ||||
-rw-r--r-- | firmware/lib/include/vboot_kernel.h | 5 | ||||
-rw-r--r-- | firmware/lib/vboot_api_kernel.c | 84 | ||||
-rw-r--r-- | firmware/lib20/api_kernel.c | 97 |
5 files changed, 216 insertions, 184 deletions
diff --git a/firmware/2lib/2kernel.c b/firmware/2lib/2kernel.c new file mode 100644 index 00000000..f49b6dea --- /dev/null +++ b/firmware/2lib/2kernel.c @@ -0,0 +1,193 @@ +/* Copyright 2020 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. + * + * Kernel selection, loading, verification, and booting. + */ + +#include "2common.h" +#include "2kernel.h" +#include "2misc.h" +#include "2nvstorage.h" +#include "2rsa.h" +#include "2secdata.h" +#include "vb2_common.h" +#include "vboot_kernel.h" + +/** + * Reset any NVRAM requests. + * + * @param ctx Vboot context + * @return 1 if a reboot is required, 0 otherwise. + */ +static int vb2_reset_nv_requests(struct vb2_context *ctx) +{ + int need_reboot = 0; + + if (vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST)) { + VB2_DEBUG("Unset display request (undo display init)\n"); + vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 0); + need_reboot = 1; + } + + if (vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST)) { + VB2_DEBUG("Unset diagnostic request (undo display init)\n"); + vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 0); + need_reboot = 1; + } + + return need_reboot; +} + +vb2_error_t vb2_normal_boot(struct vb2_context *ctx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + uint32_t max_rollforward = vb2_nv_get(ctx, + VB2_NV_KERNEL_MAX_ROLLFORWARD); + + /* Boot from fixed disk only */ + VB2_DEBUG("Entering\n"); + + if (vb2_reset_nv_requests(ctx)) { + VB2_DEBUG("Normal mode: reboot to reset NVRAM requests\n"); + return VBERROR_REBOOT_REQUIRED; + } + + vb2_error_t rv = VbTryLoadKernel(ctx, VB_DISK_FLAG_FIXED); + + VB2_DEBUG("Checking if TPM kernel version needs advancing\n"); + + /* + * Special case for when we're trying a slot with new firmware. + * Firmware updates also usually change the kernel key, which means + * that the new firmware can only boot a new kernel, and the old + * firmware in the previous slot can only boot the previous kernel. + * + * Don't roll-forward the kernel version, because we don't yet know if + * the new kernel will successfully boot. + */ + if (vb2_nv_get(ctx, VB2_NV_FW_RESULT) == VB2_FW_RESULT_TRYING) { + VB2_DEBUG("Trying new FW; skip kernel version roll-forward.\n"); + return rv; + } + + /* + * Limit kernel version rollforward if needed. Can't limit kernel + * version to less than the version currently in the TPM. That is, + * we're limiting rollforward, not allowing rollback. + */ + if (max_rollforward < sd->kernel_version_secdata) + max_rollforward = sd->kernel_version_secdata; + + if (sd->kernel_version > max_rollforward) { + VB2_DEBUG("Limiting TPM kernel version roll-forward " + "to %#x < %#x\n", + max_rollforward, sd->kernel_version); + + sd->kernel_version = max_rollforward; + } + + if (sd->kernel_version > sd->kernel_version_secdata) { + vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS, + sd->kernel_version); + } + + return rv; +} + +int vb2api_is_developer_signed(struct vb2_context *ctx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + + if (!sd->kernel_key_offset || !sd->kernel_key_size) { + VB2_REC_OR_DIE(ctx, "Cannot call this before kernel_phase1!\n"); + return 0; + } + + struct vb2_public_key key; + if (vb2_unpack_key(&key, vb2_member_of(sd, sd->kernel_key_offset))) + return 0; + + /* This is a debugging aid, not a security-relevant feature. There's no + reason to hardcode the whole key or waste time computing a hash. Just + spot check the starting bytes of the pseudorandom part of the key. */ + uint32_t devkey_n0inv = ctx->flags & VB2_CONTEXT_RECOVERY_MODE ? + 0x18cebcf5 : /* recovery_key.vbpubk @0x24 */ + 0xe0cd87d9; /* kernel_subkey.vbpubk @0x24 */ + + if (key.n0inv == devkey_n0inv) + return 1; + + return 0; +} + +vb2_error_t vb2api_kernel_phase1(struct vb2_context *ctx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + struct vb2_workbuf wb; + struct vb2_packed_key *packed_key; + vb2_error_t rv; + + vb2_workbuf_from_ctx(ctx, &wb); + + /* + * Init secdata_kernel and secdata_fwmp spaces. No need to init + * secdata_firmware, since it was already read during firmware + * verification. Ignore errors in recovery mode. + */ + rv = vb2_secdata_kernel_init(ctx); + if (rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { + VB2_DEBUG("TPM: init secdata_kernel returned %#x\n", rv); + vb2api_fail(ctx, VB2_RECOVERY_SECDATA_KERNEL_INIT, rv); + return rv; + } + rv = vb2_secdata_fwmp_init(ctx); + if (rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { + VB2_DEBUG("TPM: init secdata_fwmp returned %#x\n", rv); + vb2api_fail(ctx, VB2_RECOVERY_SECDATA_FWMP_INIT, rv); + return rv; + } + + /* Read kernel version from secdata. */ + sd->kernel_version_secdata = + vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_VERSIONS); + sd->kernel_version = sd->kernel_version_secdata; + + /* Find the key to use to verify the kernel keyblock */ + if ((ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { + /* Load recovery key from GBB. */ + rv = vb2_gbb_read_recovery_key(ctx, &packed_key, NULL, &wb); + if (rv) { + if (vb2_allow_recovery(ctx)) + VB2_DIE("GBB read recovery key failed.\n"); + else + /* + * If we're headed for the BROKEN screen, + * we won't need the recovery key. Just + * short-circuit with success. + */ + return VB2_SUCCESS; + } + } else { + /* Kernel subkey from firmware preamble */ + struct vb2_fw_preamble *pre; + + /* Make sure we have a firmware preamble loaded */ + if (!sd->preamble_size) + return VB2_ERROR_API_KPHASE1_PREAMBLE; + + pre = (struct vb2_fw_preamble *) + vb2_member_of(sd, sd->preamble_offset); + packed_key = &pre->kernel_subkey; + } + + sd->kernel_key_offset = vb2_offset_of(sd, packed_key); + sd->kernel_key_size = packed_key->key_offset + packed_key->key_size; + + vb2_set_workbuf_used(ctx, vb2_offset_of(sd, wb.buf)); + + if (vb2api_is_developer_signed(ctx)) + VB2_DEBUG("This is developer-signed firmware.\n"); + + return VB2_SUCCESS; +} diff --git a/firmware/2lib/include/2kernel.h b/firmware/2lib/include/2kernel.h new file mode 100644 index 00000000..bed1a01f --- /dev/null +++ b/firmware/2lib/include/2kernel.h @@ -0,0 +1,21 @@ +/* Copyright 2020 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. + * + * Kernel selection, loading, verification, and booting. + */ + +#ifndef VBOOT_REFERENCE_2KERNEL_H_ +#define VBOOT_REFERENCE_2KERNEL_H_ + +#include "2common.h" + +/** + * Handle a normal boot. + * + * @param ctx Vboot context. + * @return VB2_SUCCESS, or error code on error. + */ +vb2_error_t vb2_normal_boot(struct vb2_context *ctx); + +#endif /* VBOOT_REFERENCE_2KERNEL_H_ */ diff --git a/firmware/lib/include/vboot_kernel.h b/firmware/lib/include/vboot_kernel.h index eb15e5e2..81e523d9 100644 --- a/firmware/lib/include/vboot_kernel.h +++ b/firmware/lib/include/vboot_kernel.h @@ -127,11 +127,6 @@ vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t get_info_flags); int VbUserConfirms(struct vb2_context *ctx, uint32_t confirm_flags); /** - * Handle a normal boot. - */ -vb2_error_t VbBootNormal(struct vb2_context *ctx); - -/** * Handle a developer-mode boot using legacy clamshell UI. */ vb2_error_t VbBootDeveloperLegacyClamshell(struct vb2_context *ctx); diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c index 42dded12..82b2b033 100644 --- a/firmware/lib/vboot_api_kernel.c +++ b/firmware/lib/vboot_api_kernel.c @@ -7,6 +7,7 @@ #include "2api.h" #include "2common.h" +#include "2kernel.h" #include "2misc.h" #include "2nvstorage.h" #include "2rsa.h" @@ -141,87 +142,6 @@ vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t get_info_flags) return rv; } -/** - * Reset any NVRAM requests. - * - * @param ctx Vboot context - * @return 1 if a reboot is required, 0 otherwise. - */ -static int vb2_reset_nv_requests(struct vb2_context *ctx) -{ - int need_reboot = 0; - - if (vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST)) { - VB2_DEBUG("Unset display request (undo display init)\n"); - vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 0); - need_reboot = 1; - } - - if (vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST)) { - VB2_DEBUG("Unset diagnostic request (undo display init)\n"); - vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 0); - need_reboot = 1; - } - - return need_reboot; -} - -vb2_error_t VbBootNormal(struct vb2_context *ctx) -{ - struct vb2_shared_data *sd = vb2_get_sd(ctx); - uint32_t max_rollforward = vb2_nv_get(ctx, - VB2_NV_KERNEL_MAX_ROLLFORWARD); - - /* Boot from fixed disk only */ - VB2_DEBUG("Entering\n"); - - if (vb2_reset_nv_requests(ctx)) { - VB2_DEBUG("Normal mode: reboot to reset NVRAM requests\n"); - return VBERROR_REBOOT_REQUIRED; - } - - vb2_error_t rv = VbTryLoadKernel(ctx, VB_DISK_FLAG_FIXED); - - VB2_DEBUG("Checking if TPM kernel version needs advancing\n"); - - /* - * Special case for when we're trying a slot with new firmware. - * Firmware updates also usually change the kernel key, which means - * that the new firmware can only boot a new kernel, and the old - * firmware in the previous slot can only boot the previous kernel. - * - * Don't roll-forward the kernel version, because we don't yet know if - * the new kernel will successfully boot. - */ - if (vb2_nv_get(ctx, VB2_NV_FW_RESULT) == VB2_FW_RESULT_TRYING) { - VB2_DEBUG("Trying new FW; skip kernel version roll-forward.\n"); - return rv; - } - - /* - * Limit kernel version rollforward if needed. Can't limit kernel - * version to less than the version currently in the TPM. That is, - * we're limiting rollforward, not allowing rollback. - */ - if (max_rollforward < sd->kernel_version_secdata) - max_rollforward = sd->kernel_version_secdata; - - if (sd->kernel_version > max_rollforward) { - VB2_DEBUG("Limiting TPM kernel version roll-forward " - "to %#x < %#x\n", - max_rollforward, sd->kernel_version); - - sd->kernel_version = max_rollforward; - } - - if (sd->kernel_version > sd->kernel_version_secdata) { - vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS, - sd->kernel_version); - } - - return rv; -} - static vb2_error_t vb2_kernel_init_kparams(struct vb2_context *ctx, VbSelectAndLoadKernelParams *kparams) { @@ -350,7 +270,7 @@ vb2_error_t VbSelectAndLoadKernel(struct vb2_context *ctx, rv = VbBootDeveloperLegacyClamshell(ctx); } else { /* Normal boot */ - rv = VbBootNormal(ctx); + rv = vb2_normal_boot(ctx); } if (VB2_SUCCESS == rv && (ctx->flags & VB2_CONTEXT_NO_BOOT)) { diff --git a/firmware/lib20/api_kernel.c b/firmware/lib20/api_kernel.c index 8b146093..36456f61 100644 --- a/firmware/lib20/api_kernel.c +++ b/firmware/lib20/api_kernel.c @@ -16,103 +16,6 @@ #include "vb2_common.h" #include "vboot_struct.h" -int vb2api_is_developer_signed(struct vb2_context *ctx) -{ - struct vb2_shared_data *sd = vb2_get_sd(ctx); - - if (!sd->kernel_key_offset || !sd->kernel_key_size) { - VB2_REC_OR_DIE(ctx, "Cannot call this before kernel_phase1!\n"); - return 0; - } - - struct vb2_public_key key; - if (vb2_unpack_key(&key, vb2_member_of(sd, sd->kernel_key_offset))) - return 0; - - /* This is a debugging aid, not a security-relevant feature. There's no - reason to hardcode the whole key or waste time computing a hash. Just - spot check the starting bytes of the pseudorandom part of the key. */ - uint32_t devkey_n0inv = ctx->flags & VB2_CONTEXT_RECOVERY_MODE ? - 0x18cebcf5 : /* recovery_key.vbpubk @0x24 */ - 0xe0cd87d9; /* kernel_subkey.vbpubk @0x24 */ - - if (key.n0inv == devkey_n0inv) - return 1; - - return 0; -} - -vb2_error_t vb2api_kernel_phase1(struct vb2_context *ctx) -{ - struct vb2_shared_data *sd = vb2_get_sd(ctx); - struct vb2_workbuf wb; - struct vb2_packed_key *packed_key; - vb2_error_t rv; - - vb2_workbuf_from_ctx(ctx, &wb); - - /* - * Init secdata_kernel and secdata_fwmp spaces. No need to init - * secdata_firmware, since it was already read during firmware - * verification. Ignore errors in recovery mode. - */ - rv = vb2_secdata_kernel_init(ctx); - if (rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { - VB2_DEBUG("TPM: init secdata_kernel returned %#x\n", rv); - vb2api_fail(ctx, VB2_RECOVERY_SECDATA_KERNEL_INIT, rv); - return rv; - } - rv = vb2_secdata_fwmp_init(ctx); - if (rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { - VB2_DEBUG("TPM: init secdata_fwmp returned %#x\n", rv); - vb2api_fail(ctx, VB2_RECOVERY_SECDATA_FWMP_INIT, rv); - return rv; - } - - /* Read kernel version from secdata. */ - sd->kernel_version_secdata = - vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_VERSIONS); - sd->kernel_version = sd->kernel_version_secdata; - - /* Find the key to use to verify the kernel keyblock */ - if ((ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { - /* Load recovery key from GBB. */ - rv = vb2_gbb_read_recovery_key(ctx, &packed_key, NULL, &wb); - if (rv) { - if (vb2_allow_recovery(ctx)) - VB2_DIE("GBB read recovery key failed.\n"); - else - /* - * If we're headed for the BROKEN screen, - * we won't need the recovery key. Just - * short-circuit with success. - */ - return VB2_SUCCESS; - } - } else { - /* Kernel subkey from firmware preamble */ - struct vb2_fw_preamble *pre; - - /* Make sure we have a firmware preamble loaded */ - if (!sd->preamble_size) - return VB2_ERROR_API_KPHASE1_PREAMBLE; - - pre = (struct vb2_fw_preamble *) - vb2_member_of(sd, sd->preamble_offset); - packed_key = &pre->kernel_subkey; - } - - sd->kernel_key_offset = vb2_offset_of(sd, packed_key); - sd->kernel_key_size = packed_key->key_offset + packed_key->key_size; - - vb2_set_workbuf_used(ctx, vb2_offset_of(sd, wb.buf)); - - if (vb2api_is_developer_signed(ctx)) - VB2_DEBUG("This is developer-signed firmware.\n"); - - return VB2_SUCCESS; -} - vb2_error_t vb2api_load_kernel_vblock(struct vb2_context *ctx) { vb2_error_t rv; |