summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Kitching <kitching@google.com>2020-03-06 14:56:14 +0800
committerCommit Bot <commit-bot@chromium.org>2020-03-09 08:43:37 +0000
commitcebb4f5912d2a72f86e43d9552edcf881806c6b9 (patch)
tree8ff44bf028a1a98f81ea62684876e224f5d35985
parent4da0add3b390e9aecd2113375abae874318c7cf4 (diff)
downloadvboot-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>
-rw-r--r--Makefile4
-rw-r--r--firmware/2lib/2kernel.c193
-rw-r--r--firmware/2lib/include/2kernel.h21
-rw-r--r--firmware/lib/include/vboot_kernel.h5
-rw-r--r--firmware/lib/vboot_api_kernel.c84
-rw-r--r--firmware/lib20/api_kernel.c97
-rw-r--r--tests/vb20_api_kernel_tests.c115
-rw-r--r--tests/vb2_kernel_tests.c270
-rw-r--r--tests/vboot_legacy_clamshell_tests.c17
-rw-r--r--tests/vboot_legacy_menu_tests.c3
10 files changed, 501 insertions, 308 deletions
diff --git a/Makefile b/Makefile
index 48729175..58f930a2 100644
--- a/Makefile
+++ b/Makefile
@@ -357,6 +357,7 @@ FWLIB_SRCS = \
firmware/2lib/2ec_sync.c \
firmware/2lib/2gbb.c \
firmware/2lib/2hmac.c \
+ firmware/2lib/2kernel.c \
firmware/2lib/2misc.c \
firmware/2lib/2nvstorage.c \
firmware/2lib/2rsa.c \
@@ -479,6 +480,7 @@ HOSTLIB_SRCS = \
firmware/2lib/2context.c \
firmware/2lib/2crc8.c \
firmware/2lib/2hmac.c \
+ firmware/2lib/2kernel.c \
firmware/2lib/2nvstorage.c \
firmware/2lib/2rsa.c \
firmware/2lib/2sha1.c \
@@ -695,6 +697,7 @@ TEST2X_NAMES = \
tests/vb2_ec_sync_tests \
tests/vb2_gbb_tests \
tests/vb2_host_key_tests \
+ tests/vb2_kernel_tests \
tests/vb2_misc_tests \
tests/vb2_nvstorage_tests \
tests/vb2_rsa_utility_tests \
@@ -1204,6 +1207,7 @@ run2tests: install_for_test
${RUNTEST} ${BUILD_RUN}/tests/vb2_ec_sync_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_gbb_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_host_key_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vb2_kernel_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_misc_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_nvstorage_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_rsa_utility_tests
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;
diff --git a/tests/vb20_api_kernel_tests.c b/tests/vb20_api_kernel_tests.c
index dad612f0..aa7686b0 100644
--- a/tests/vb20_api_kernel_tests.c
+++ b/tests/vb20_api_kernel_tests.c
@@ -223,120 +223,6 @@ vb2_error_t vb2_verify_digest(const struct vb2_public_key *key,
/* Tests */
-static void phase1_tests(void)
-{
- struct vb2_packed_key *k;
- uint32_t wb_used_before;
-
- /* Test successful call */
- reset_common_data(FOR_PHASE1);
- TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 good");
- /* Make sure normal key was loaded */
- TEST_EQ(sd->kernel_key_offset, sd->preamble_offset +
- offsetof(struct vb2_fw_preamble, kernel_subkey),
- " workbuf key offset");
- k = vb2_member_of(sd, sd->kernel_key_offset);
- TEST_EQ(sd->kernel_key_size, k->key_offset + k->key_size,
- " workbuf key size");
- TEST_EQ(sd->workbuf_used,
- vb2_wb_round_up(sd->kernel_key_offset +
- sd->kernel_key_size),
- " workbuf used");
- TEST_EQ(k->algorithm, 7, " key algorithm");
- TEST_EQ(k->key_size, sizeof(fw_kernel_key_data), " key_size");
- TEST_EQ(memcmp((uint8_t *)k + k->key_offset, fw_kernel_key_data,
- k->key_size), 0, " key data");
- TEST_EQ(sd->kernel_version_secdata, 0x20002,
- " secdata_kernel version");
-
- /* Test successful call in recovery mode */
- reset_common_data(FOR_PHASE1);
- ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
- /* No preamble needed in recovery mode */
- sd->workbuf_used = sd->preamble_offset;
- sd->preamble_offset = sd->preamble_size = 0;
- wb_used_before = sd->workbuf_used;
- TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 rec good");
- /* Make sure recovery key was loaded */
- TEST_EQ(sd->kernel_key_offset, wb_used_before,
- " workbuf key offset");
- k = vb2_member_of(sd, sd->kernel_key_offset);
- TEST_EQ(sd->kernel_key_size, k->key_offset + k->key_size,
- " workbuf key size");
- TEST_EQ(sd->workbuf_used,
- vb2_wb_round_up(sd->kernel_key_offset +
- sd->kernel_key_size),
- " workbuf used");
- TEST_EQ(k->algorithm, 11, " key algorithm");
- TEST_EQ(k->key_size, sizeof(mock_gbb.recovery_key_data), " key_size");
- TEST_EQ(memcmp((uint8_t *)k + k->key_offset,
- mock_gbb.recovery_key_data, k->key_size), 0,
- " key data");
- TEST_EQ(sd->kernel_version_secdata, 0x20002,
- " secdata_kernel version");
-
- /* Bad secdata_kernel causes failure in normal mode only */
- reset_common_data(FOR_PHASE1);
- ctx->secdata_kernel[2] ^= 0x33; /* 3rd byte is CRC */
- TEST_EQ(vb2api_kernel_phase1(ctx), VB2_ERROR_SECDATA_KERNEL_CRC,
- "phase1 bad secdata_kernel");
- TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
- VB2_RECOVERY_SECDATA_KERNEL_INIT, " recovery reason");
-
- reset_common_data(FOR_PHASE1);
- ctx->secdata_kernel[0] ^= 0x33;
- ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
- TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 bad secdata_kernel rec");
- TEST_EQ(sd->kernel_version_secdata, 0, " secdata_kernel version");
- TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
- VB2_RECOVERY_NOT_REQUESTED, " no recovery");
-
- /* Bad secdata_fwmp causes failure in normal mode only */
- reset_common_data(FOR_PHASE1);
- mock_secdata_fwmp_check_retval = VB2_ERROR_SECDATA_FWMP_CRC;
- TEST_EQ(vb2api_kernel_phase1(ctx), mock_secdata_fwmp_check_retval,
- "phase1 bad secdata_fwmp");
- TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
- VB2_RECOVERY_SECDATA_FWMP_INIT, " recovery reason");
-
- reset_common_data(FOR_PHASE1);
- mock_secdata_fwmp_check_retval = VB2_ERROR_SECDATA_FWMP_CRC;
- ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
- TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 bad secdata_fwmp rec");
- TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
- VB2_RECOVERY_NOT_REQUESTED, " no recovery");
-
- /* Failures while reading recovery key */
- reset_common_data(FOR_PHASE1);
- ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
- mock_gbb.h.recovery_key_size = sd->workbuf_size - 1;
- mock_gbb.recovery_key.key_size =
- mock_gbb.h.recovery_key_size - sizeof(mock_gbb.recovery_key);
- TEST_EQ(vb2api_kernel_phase1(ctx), VB2_SUCCESS,
- "phase1 rec workbuf key");
- TEST_EQ(sd->kernel_key_offset, 0, " workbuf key offset");
- TEST_EQ(sd->kernel_key_size, 0, " workbuf key size");
- mock_gbb.h.flags |= VB2_GBB_FLAG_FORCE_MANUAL_RECOVERY;
- TEST_ABORT(vb2api_kernel_phase1(ctx), " fatal for manual recovery");
-
- reset_common_data(FOR_PHASE1);
- ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
- mock_read_res_fail_on_call = 1;
- TEST_EQ(vb2api_kernel_phase1(ctx), VB2_SUCCESS,
- "phase1 rec gbb read key");
- TEST_EQ(sd->kernel_key_offset, 0, " workbuf key offset");
- TEST_EQ(sd->kernel_key_size, 0, " workbuf key size");
- mock_gbb.h.flags |= VB2_GBB_FLAG_FORCE_MANUAL_RECOVERY;
- mock_read_res_fail_on_call = 1;
- TEST_ABORT(vb2api_kernel_phase1(ctx), " fatal for manual recovery");
-
- /* Failures while parsing subkey from firmware preamble */
- reset_common_data(FOR_PHASE1);
- sd->preamble_size = 0;
- TEST_EQ(vb2api_kernel_phase1(ctx), VB2_ERROR_API_KPHASE1_PREAMBLE,
- "phase1 fw preamble");
-}
-
static void load_kernel_vblock_tests(void)
{
reset_common_data(FOR_PHASE1);
@@ -472,7 +358,6 @@ static void phase3_tests(void)
int main(int argc, char* argv[])
{
- phase1_tests();
load_kernel_vblock_tests();
get_kernel_size_tests();
verify_kernel_data_tests();
diff --git a/tests/vb2_kernel_tests.c b/tests/vb2_kernel_tests.c
new file mode 100644
index 00000000..bd64fb08
--- /dev/null
+++ b/tests/vb2_kernel_tests.c
@@ -0,0 +1,270 @@
+/* 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.
+ *
+ * Tests for kernel selection, loading, verification, and booting.
+ */
+
+#include "2api.h"
+#include "2common.h"
+#include "2misc.h"
+#include "2nvstorage.h"
+#include "2rsa.h"
+#include "2secdata.h"
+#include "2sysincludes.h"
+#include "test_common.h"
+#include "vb2_common.h"
+#include "vboot_struct.h"
+
+/* Common context for tests */
+static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]
+ __attribute__((aligned(VB2_WORKBUF_ALIGN)));
+static struct vb2_context *ctx;
+static struct vb2_shared_data *sd;
+static struct vb2_fw_preamble *fwpre;
+static const char fw_kernel_key_data[36] = "Test kernel key data";
+
+/* Mocked function data */
+
+static struct {
+ struct vb2_gbb_header h;
+ struct vb2_packed_key recovery_key;
+ char recovery_key_data[32];
+} mock_gbb;
+
+static int mock_read_res_fail_on_call;
+static int mock_secdata_fwmp_check_retval;
+
+/* Type of test to reset for */
+enum reset_type {
+ FOR_PHASE1,
+};
+
+static void reset_common_data(enum reset_type t)
+{
+ struct vb2_packed_key *k;
+
+ memset(workbuf, 0xaa, sizeof(workbuf));
+
+ TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx),
+ "vb2api_init failed");
+
+ sd = vb2_get_sd(ctx);
+ vb2_nv_init(ctx);
+
+ vb2api_secdata_kernel_create(ctx);
+ vb2_secdata_kernel_init(ctx);
+ vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS, 0x20002);
+
+ mock_read_res_fail_on_call = 0;
+ mock_secdata_fwmp_check_retval = VB2_SUCCESS;
+
+ /* Recovery key in mock GBB */
+ memset(&mock_gbb, 0, sizeof(mock_gbb));
+ mock_gbb.recovery_key.algorithm = 11;
+ mock_gbb.recovery_key.key_offset =
+ vb2_offset_of(&mock_gbb.recovery_key,
+ &mock_gbb.recovery_key_data);
+ mock_gbb.recovery_key.key_size = sizeof(mock_gbb.recovery_key_data);
+ strcpy(mock_gbb.recovery_key_data, "The recovery key");
+ mock_gbb.h.recovery_key_offset =
+ vb2_offset_of(&mock_gbb, &mock_gbb.recovery_key);
+ mock_gbb.h.recovery_key_size =
+ mock_gbb.recovery_key.key_offset +
+ mock_gbb.recovery_key.key_size;
+
+
+ if (t == FOR_PHASE1) {
+ uint8_t *kdata;
+
+ /* Create mock firmware preamble in the context */
+ sd->preamble_offset = sd->workbuf_used;
+ fwpre = (struct vb2_fw_preamble *)
+ vb2_member_of(sd, sd->preamble_offset);
+ k = &fwpre->kernel_subkey;
+ kdata = (uint8_t *)fwpre + sizeof(*fwpre);
+ memcpy(kdata, fw_kernel_key_data, sizeof(fw_kernel_key_data));
+ k->algorithm = 7;
+ k->key_offset = vb2_offset_of(k, kdata);
+ k->key_size = sizeof(fw_kernel_key_data);
+ sd->preamble_size = sizeof(*fwpre) + k->key_size;
+ vb2_set_workbuf_used(ctx,
+ sd->preamble_offset + sd->preamble_size);
+
+ /* Needed to check that secdata_kernel initialization is
+ performed by phase1 function. */
+ sd->status &= ~VB2_SD_STATUS_SECDATA_KERNEL_INIT;
+
+ }
+};
+
+/* Mocked functions */
+
+vb2_error_t vb2api_secdata_fwmp_check(struct vb2_context *c, uint8_t *size)
+{
+ return mock_secdata_fwmp_check_retval;
+}
+
+struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c)
+{
+ return &mock_gbb.h;
+}
+
+vb2_error_t vb2ex_read_resource(struct vb2_context *c,
+ enum vb2_resource_index index, uint32_t offset,
+ void *buf, uint32_t size)
+{
+ uint8_t *rptr;
+ uint32_t rsize;
+
+ if (--mock_read_res_fail_on_call == 0)
+ return VB2_ERROR_MOCK;
+
+ switch(index) {
+ case VB2_RES_GBB:
+ rptr = (uint8_t *)&mock_gbb;
+ rsize = sizeof(mock_gbb);
+ break;
+ default:
+ return VB2_ERROR_EX_READ_RESOURCE_INDEX;
+ }
+
+ if (offset > rsize || offset + size > rsize)
+ return VB2_ERROR_EX_READ_RESOURCE_SIZE;
+
+ memcpy(buf, rptr + offset, size);
+ return VB2_SUCCESS;
+}
+
+/* Tests */
+
+static void phase1_tests(void)
+{
+ struct vb2_packed_key *k;
+ uint32_t wb_used_before;
+
+ /* Test successful call */
+ reset_common_data(FOR_PHASE1);
+ TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 good");
+ /* Make sure normal key was loaded */
+ TEST_EQ(sd->kernel_key_offset, sd->preamble_offset +
+ offsetof(struct vb2_fw_preamble, kernel_subkey),
+ " workbuf key offset");
+ k = vb2_member_of(sd, sd->kernel_key_offset);
+ TEST_EQ(sd->kernel_key_size, k->key_offset + k->key_size,
+ " workbuf key size");
+ TEST_EQ(sd->workbuf_used,
+ vb2_wb_round_up(sd->kernel_key_offset +
+ sd->kernel_key_size),
+ " workbuf used");
+ TEST_EQ(k->algorithm, 7, " key algorithm");
+ TEST_EQ(k->key_size, sizeof(fw_kernel_key_data), " key_size");
+ TEST_EQ(memcmp((uint8_t *)k + k->key_offset, fw_kernel_key_data,
+ k->key_size), 0, " key data");
+ TEST_EQ(sd->kernel_version_secdata, 0x20002,
+ " secdata_kernel version");
+
+ /* Test successful call in recovery mode */
+ reset_common_data(FOR_PHASE1);
+ ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+ /* No preamble needed in recovery mode */
+ sd->workbuf_used = sd->preamble_offset;
+ sd->preamble_offset = sd->preamble_size = 0;
+ wb_used_before = sd->workbuf_used;
+ TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 rec good");
+ /* Make sure recovery key was loaded */
+ TEST_EQ(sd->kernel_key_offset, wb_used_before,
+ " workbuf key offset");
+ k = vb2_member_of(sd, sd->kernel_key_offset);
+ TEST_EQ(sd->kernel_key_size, k->key_offset + k->key_size,
+ " workbuf key size");
+ TEST_EQ(sd->workbuf_used,
+ vb2_wb_round_up(sd->kernel_key_offset +
+ sd->kernel_key_size),
+ " workbuf used");
+ TEST_EQ(k->algorithm, 11, " key algorithm");
+ TEST_EQ(k->key_size, sizeof(mock_gbb.recovery_key_data), " key_size");
+ TEST_EQ(memcmp((uint8_t *)k + k->key_offset,
+ mock_gbb.recovery_key_data, k->key_size), 0,
+ " key data");
+ TEST_EQ(sd->kernel_version_secdata, 0x20002,
+ " secdata_kernel version");
+
+ /* Bad secdata_kernel causes failure in normal mode only */
+ reset_common_data(FOR_PHASE1);
+ ctx->secdata_kernel[2] ^= 0x33; /* 3rd byte is CRC */
+ TEST_EQ(vb2api_kernel_phase1(ctx), VB2_ERROR_SECDATA_KERNEL_CRC,
+ "phase1 bad secdata_kernel");
+ TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
+ VB2_RECOVERY_SECDATA_KERNEL_INIT, " recovery reason");
+
+ reset_common_data(FOR_PHASE1);
+ ctx->secdata_kernel[0] ^= 0x33;
+ ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+ TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 bad secdata_kernel rec");
+ TEST_EQ(sd->kernel_version_secdata, 0, " secdata_kernel version");
+ TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
+ VB2_RECOVERY_NOT_REQUESTED, " no recovery");
+
+ /* Bad secdata_fwmp causes failure in normal mode only */
+ reset_common_data(FOR_PHASE1);
+ mock_secdata_fwmp_check_retval = VB2_ERROR_SECDATA_FWMP_CRC;
+ TEST_EQ(vb2api_kernel_phase1(ctx), mock_secdata_fwmp_check_retval,
+ "phase1 bad secdata_fwmp");
+ TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
+ VB2_RECOVERY_SECDATA_FWMP_INIT, " recovery reason");
+
+ reset_common_data(FOR_PHASE1);
+ mock_secdata_fwmp_check_retval = VB2_ERROR_SECDATA_FWMP_CRC;
+ ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+ TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 bad secdata_fwmp rec");
+ TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
+ VB2_RECOVERY_NOT_REQUESTED, " no recovery");
+
+ /* Failures while reading recovery key */
+ reset_common_data(FOR_PHASE1);
+ ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+ mock_gbb.h.recovery_key_size = sd->workbuf_size - 1;
+ mock_gbb.recovery_key.key_size =
+ mock_gbb.h.recovery_key_size - sizeof(mock_gbb.recovery_key);
+ TEST_EQ(vb2api_kernel_phase1(ctx), VB2_SUCCESS,
+ "phase1 rec workbuf key");
+ TEST_EQ(sd->kernel_key_offset, 0, " workbuf key offset");
+ TEST_EQ(sd->kernel_key_size, 0, " workbuf key size");
+ mock_gbb.h.flags |= VB2_GBB_FLAG_FORCE_MANUAL_RECOVERY;
+ TEST_ABORT(vb2api_kernel_phase1(ctx), " fatal for manual recovery");
+
+ reset_common_data(FOR_PHASE1);
+ ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+ mock_read_res_fail_on_call = 1;
+ TEST_EQ(vb2api_kernel_phase1(ctx), VB2_SUCCESS,
+ "phase1 rec gbb read key");
+ TEST_EQ(sd->kernel_key_offset, 0, " workbuf key offset");
+ TEST_EQ(sd->kernel_key_size, 0, " workbuf key size");
+ mock_gbb.h.flags |= VB2_GBB_FLAG_FORCE_MANUAL_RECOVERY;
+ mock_read_res_fail_on_call = 1;
+ TEST_ABORT(vb2api_kernel_phase1(ctx), " fatal for manual recovery");
+
+ /* Failures while parsing subkey from firmware preamble */
+ reset_common_data(FOR_PHASE1);
+ sd->preamble_size = 0;
+ TEST_EQ(vb2api_kernel_phase1(ctx), VB2_ERROR_API_KPHASE1_PREAMBLE,
+ "phase1 fw preamble");
+}
+
+static void normal_boot_tests(void)
+{
+ /*
+ * TODO: vb2_normal_boot() tests go here. Relocate from
+ * vboot_legacy_clamshell_tests.c, and remove comment in
+ * vboot_legacy_menu_tests.c.
+ */
+}
+
+int main(int argc, char* argv[])
+{
+ phase1_tests();
+ normal_boot_tests();
+
+ return gTestSuccess ? 0 : 255;
+}
diff --git a/tests/vboot_legacy_clamshell_tests.c b/tests/vboot_legacy_clamshell_tests.c
index 9c7e0c71..4f0849d3 100644
--- a/tests/vboot_legacy_clamshell_tests.c
+++ b/tests/vboot_legacy_clamshell_tests.c
@@ -6,6 +6,7 @@
*/
#include "2common.h"
+#include "2kernel.h"
#include "2misc.h"
#include "2nvstorage.h"
#include "2secdata.h"
@@ -484,25 +485,25 @@ static void VbBootTest(void)
ResetMocks();
vbtlk_expect_fixed = 1;
vbtlk_retval = VB2_SUCCESS;
- TEST_EQ(VbBootNormal(ctx), VB2_SUCCESS,
- "VbBootNormal() returns VB2_SUCCESS");
+ TEST_EQ(vb2_normal_boot(ctx), VB2_SUCCESS,
+ "vb2_normal_boot() returns VB2_SUCCESS");
ResetMocks();
vbtlk_expect_fixed = 1;
- TEST_EQ(VbBootNormal(ctx), VB2_ERROR_MOCK,
- "VbBootNormal() returns VB2_ERROR_MOCK");
+ TEST_EQ(vb2_normal_boot(ctx), VB2_ERROR_MOCK,
+ "vb2_normal_boot() returns VB2_ERROR_MOCK");
ResetMocks();
vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 1);
- TEST_EQ(VbBootNormal(ctx), VBERROR_REBOOT_REQUIRED,
- "VbBootNormal() reboot to reset NVRAM display request");
+ TEST_EQ(vb2_normal_boot(ctx), VBERROR_REBOOT_REQUIRED,
+ "vb2_normal_boot() reboot to reset NVRAM display request");
TEST_EQ(vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST), 0,
" display request reset");
ResetMocks();
vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1);
- TEST_EQ(VbBootNormal(ctx), VBERROR_REBOOT_REQUIRED,
- "VbBootNormal() reboot to reset NVRAM diag request");
+ TEST_EQ(vb2_normal_boot(ctx), VBERROR_REBOOT_REQUIRED,
+ "vb2_normal_boot() reboot to reset NVRAM diag request");
TEST_EQ(vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST), 0,
" diag request reset");
}
diff --git a/tests/vboot_legacy_menu_tests.c b/tests/vboot_legacy_menu_tests.c
index a9af7ddd..57dcb4a6 100644
--- a/tests/vboot_legacy_menu_tests.c
+++ b/tests/vboot_legacy_menu_tests.c
@@ -235,7 +235,8 @@ vb2_error_t vb2_enable_developer_mode(struct vb2_context *c)
/* Tests */
/*
- * VbBootNormal tests: Please see VbBootTest in vboot_legacy_clamshell_tests.c
+ * vb2_normal_boot tests: Please see VbBootTest in
+ * vboot_legacy_clamshell_tests.c.
*/
static void VbBootDevTest(void)