summaryrefslogtreecommitdiff
path: root/firmware/lib/vboot_api_kernel.c
diff options
context:
space:
mode:
authorJoel Kitching <kitching@google.com>2019-09-23 22:53:49 +0800
committerCommit Bot <commit-bot@chromium.org>2019-11-28 20:49:25 +0000
commitadb418310d2e51e2f2a0f22607989fd3f66c4433 (patch)
tree52fd1dd508adead50871a3cd87cf7cb2ee3d226a /firmware/lib/vboot_api_kernel.c
parent6ef33b990578a9583a3ac53f2c835d4e16219b25 (diff)
downloadvboot-adb418310d2e51e2f2a0f22607989fd3f66c4433.tar.gz
vboot/secdata: rewrite rollback_index and centralize reads/writes
In current kernel verification code, secdata reads and writes are spread throughout the code. vboot2's design is to use vb2_context.secdata_* for storing the state of secdata spaces, and have the caller (depthcharge) read/save this field when necessary. Centralize secdata reads/writes into the functions of secdata_tpm.c, previously known as rollback_index.c. Functions which directly read/write to the TPM space are modified to use vb2_secdata_*_get and vb2_secdata_*_set. The secure spaces get read/flushed by functions in vboot_api_kernel.c. These calls and the underlying functions from secdata_tpm.c will eventually be relocated to depthcharge. Create a new external function vb2ex_commit_data, which commits any modified nvdata/secdata. Currently the depthcharge implementation of this function only writes nvdata, but once secdata TPM drivers have been migrated from vboot_reference to depthcharge, it will also commit these data spaces. This CL also removes the VbExNvStorageRead call from vb2_kernel_setup, and the data is instead read in depthcharge CL:1819379, right before calling VbSelectAndLoadKernel. As such, both the VbExNvStorageRead and VbExNvStorageWrite functions may be removed. Finally, create a vb2_secdata_kernel_lock function, which should be used right before attempting to leave vboot (by booting an OS or chainloading to another firmware). This should eventually be exposed as a vb2ex_ API function and relocated to depthcharge. BUG=b:124141368, chromium:972956, chromium:1006689 TEST=make clean && make runtests BRANCH=none Change-Id: Ifbfb21122af0bf85e22a6d3a0d48a1db7f7c25b7 Signed-off-by: Joel Kitching <kitching@google.com> Cq-Depend: chromium:1819380, chromium:1939168 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/1728298 Tested-by: Joel Kitching <kitching@chromium.org> Reviewed-by: Andrey Pronin <apronin@chromium.org> Reviewed-by: Julius Werner <jwerner@chromium.org> Commit-Queue: Joel Kitching <kitching@chromium.org>
Diffstat (limited to 'firmware/lib/vboot_api_kernel.c')
-rw-r--r--firmware/lib/vboot_api_kernel.c205
1 files changed, 130 insertions, 75 deletions
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c
index 5408c5a3..308a3275 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -22,36 +22,20 @@
#include "vboot_test.h"
/* Global variables */
-static struct RollbackSpaceFwmp fwmp;
static LoadKernelParams lkp;
#ifdef CHROMEOS_ENVIRONMENT
-/* Global variable accessors for unit tests */
-
-struct RollbackSpaceFwmp *VbApiKernelGetFwmp(void)
-{
- return &fwmp;
-}
-
+/* Global variable accessor for unit tests */
struct LoadKernelParams *VbApiKernelGetParams(void)
{
return &lkp;
}
-
#endif
-void vb2_nv_commit(struct vb2_context *ctx)
-{
- /* Exit if nothing has changed */
- if (!(ctx->flags & VB2_CONTEXT_NVDATA_CHANGED))
- return;
-
- ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED;
- VbExNvStorageWrite(ctx->nvdata);
-}
-
static vb2_error_t handle_battery_cutoff(struct vb2_context *ctx)
{
+ vb2_error_t rv;
+
/*
* Check if we need to cut-off battery. This should be done after EC
* FW and Aux FW are updated, and before the kernel is started. This
@@ -61,8 +45,12 @@ static vb2_error_t handle_battery_cutoff(struct vb2_context *ctx)
if (vb2_nv_get(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST)) {
VB2_DEBUG("Request to cut-off battery\n");
vb2_nv_set(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST, 0);
+
/* May lose power immediately, so commit our update now. */
- vb2_nv_commit(ctx);
+ rv = vb2_commit_data(ctx);
+ if (rv)
+ return rv;
+
vb2ex_ec_battery_cutoff();
return VBERROR_SHUTDOWN_REQUESTED;
}
@@ -70,11 +58,6 @@ static vb2_error_t handle_battery_cutoff(struct vb2_context *ctx)
return VB2_SUCCESS;
}
-uint32_t vb2_get_fwmp_flags(void)
-{
- return fwmp.flags;
-}
-
vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t get_info_flags)
{
vb2_error_t rv = VBERROR_NO_DISK_FOUND;
@@ -82,7 +65,6 @@ vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t get_info_flags)
uint32_t disk_count = 0;
uint32_t i;
- lkp.fwmp = &fwmp;
lkp.disk_handle = NULL;
/* Find disks */
@@ -234,13 +216,8 @@ vb2_error_t VbBootNormal(struct vb2_context *ctx)
}
if (shared->kernel_version_tpm > shared->kernel_version_tpm_start) {
- uint32_t tpm_rv =
- RollbackKernelWrite(shared->kernel_version_tpm);
- if (tpm_rv) {
- VB2_DEBUG("Error writing kernel versions to TPM.\n");
- vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_W_ERROR, tpm_rv);
- return VBERROR_TPM_WRITE_KERNEL;
- }
+ vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS,
+ shared->kernel_version_tpm);
}
return rv;
@@ -251,6 +228,7 @@ static vb2_error_t vb2_kernel_setup(struct vb2_context *ctx,
VbSelectAndLoadKernelParams *kparams)
{
uint32_t tpm_rv;
+ vb2_error_t rv;
/* Translate vboot1 flags back to vboot2 */
if (shared->recovery_reason)
@@ -274,11 +252,9 @@ static vb2_error_t vb2_kernel_setup(struct vb2_context *ctx,
if (shared->flags & VBSD_NVDATA_V2)
ctx->flags |= VB2_CONTEXT_NVDATA_V2;
- VbExNvStorageRead(ctx->nvdata);
vb2_nv_init(ctx);
struct vb2_shared_data *sd = vb2_get_sd(ctx);
- struct vb2_gbb_header *gbb = vb2_get_gbb(ctx);
sd->recovery_reason = shared->recovery_reason;
/*
@@ -312,41 +288,53 @@ static vb2_error_t vb2_kernel_setup(struct vb2_context *ctx,
kparams->flags = 0;
memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid));
- /* Read kernel version from the TPM. Ignore errors in recovery mode. */
- tpm_rv = RollbackKernelRead(&shared->kernel_version_tpm);
- if (tpm_rv) {
- VB2_DEBUG("Unable to get kernel versions from TPM\n");
- if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
- vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_R_ERROR, tpm_rv);
- return VBERROR_TPM_READ_KERNEL;
- }
+ /*
+ * Read secdata_kernel and secdata_fwmp spaces. No need to read
+ * secdata_firmware, since it was already read during firmware
+ * verification. Ignore errors in recovery mode.
+ */
+ tpm_rv = secdata_kernel_read(ctx);
+ if (tpm_rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
+ VB2_DEBUG("TPM: read secdata_kernel returned %#x\n", tpm_rv);
+ vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_R_ERROR, tpm_rv);
+ return VB2_ERROR_SECDATA_KERNEL_READ;
}
-
- shared->kernel_version_tpm_start = shared->kernel_version_tpm;
-
- /* Read FWMP. Ignore errors in recovery mode. */
- if (gbb->flags & VB2_GBB_FLAG_DISABLE_FWMP) {
- memset(&fwmp, 0, sizeof(fwmp));
- return VB2_SUCCESS;
+ tpm_rv = secdata_fwmp_read(ctx);
+ if (tpm_rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
+ VB2_DEBUG("TPM: read secdata_fwmp returned %#x\n", tpm_rv);
+ vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_R_ERROR, tpm_rv);
+ return VB2_ERROR_SECDATA_FWMP_READ;
}
- tpm_rv = RollbackFwmpRead(&fwmp);
- if (tpm_rv) {
- VB2_DEBUG("Unable to get FWMP from TPM\n");
- if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
- vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_R_ERROR, tpm_rv);
- return VBERROR_TPM_READ_FWMP;
- }
+ /*
+ * 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 the TPM. */
+ shared->kernel_version_tpm =
+ vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_VERSIONS);
+ shared->kernel_version_tpm_start = shared->kernel_version_tpm;
return VB2_SUCCESS;
}
-static vb2_error_t vb2_kernel_phase4(struct vb2_context *ctx,
- VbSelectAndLoadKernelParams *kparams)
+static void vb2_kernel_fill_kparams(struct vb2_context *ctx,
+ VbSelectAndLoadKernelParams *kparams)
{
- struct vb2_shared_data *sd = vb2_get_sd(ctx);
-
/* Save disk parameters */
kparams->disk_handle = lkp.disk_handle;
kparams->partition_number = lkp.partition_number;
@@ -357,30 +345,89 @@ static vb2_error_t vb2_kernel_phase4(struct vb2_context *ctx,
kparams->kernel_buffer_size = lkp.kernel_buffer_size;
memcpy(kparams->partition_guid, lkp.partition_guid,
sizeof(kparams->partition_guid));
+}
- /* Lock the kernel versions if not in recovery mode */
- if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
- uint32_t tpm_rv = RollbackKernelLock(sd->recovery_reason);
- if (tpm_rv) {
- VB2_DEBUG("Error locking kernel versions.\n");
- vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_L_ERROR, tpm_rv);
- return VBERROR_TPM_LOCK_KERNEL;
- }
+vb2_error_t vb2_secdata_kernel_lock(struct vb2_context *ctx)
+{
+ uint32_t tpm_rv;
+
+ /* Skip if in recovery mode. */
+ if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE)
+ return VB2_SUCCESS;
+
+ tpm_rv = secdata_kernel_lock(ctx);
+ if (tpm_rv) {
+ VB2_DEBUG("TPM: lock secdata_kernel returned %#x\n", tpm_rv);
+ vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_L_ERROR, tpm_rv);
+ return VB2_ERROR_SECDATA_KERNEL_LOCK;
}
return VB2_SUCCESS;
}
-static void vb2_kernel_cleanup(struct vb2_context *ctx)
+vb2_error_t vb2_commit_data(struct vb2_context *ctx)
{
- vb2_nv_commit(ctx);
+ vb2_error_t call_rv;
+ vb2_error_t rv = VB2_SUCCESS;
+ uint32_t tpm_rv;
+
+ /* Write secdata spaces. vboot never writes back to secdata_fwmp. */
+ tpm_rv = secdata_firmware_write(ctx);
+ if (tpm_rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
+ VB2_DEBUG("TPM: write secdata_firmware returned %#x\n", tpm_rv);
+ vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_W_ERROR, tpm_rv);
+ rv = VB2_ERROR_SECDATA_FIRMWARE_WRITE;
+ }
+
+ tpm_rv = secdata_kernel_write(ctx);
+ if (tpm_rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
+ VB2_DEBUG("TPM: write secdata_kernel returned %#x\n", tpm_rv);
+ vb2api_fail(ctx, VB2_RECOVERY_RW_TPM_W_ERROR, tpm_rv);
+ if (rv == VB2_SUCCESS)
+ rv = VB2_ERROR_SECDATA_KERNEL_WRITE;
+ }
+
+ /* Always try to write nvdata, since it may have been changed by
+ setting a recovery reason above. */
+
+ /* TODO(chromium:972956, chromium:1006689): Currently only commits
+ nvdata, but should eventually also commit secdata. */
+ call_rv = vb2ex_commit_data(ctx);
+ switch (call_rv) {
+ case VB2_ERROR_NV_WRITE:
+ /* Don't bother with vb2api_fail since we can't write
+ nvdata anyways. */
+ if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) {
+ VB2_DEBUG("write nvdata failed\n");
+ if (rv == VB2_SUCCESS)
+ rv = call_rv;
+ } else {
+ /* Impossible to enter recovery mode */
+ VB2_DIE("write nvdata failed\n");
+ }
+ break;
+
+ case VB2_SUCCESS:
+ break;
+
+ default:
+ VB2_DEBUG("unknown commit error: %#x\n", call_rv);
+ if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE) &&
+ rv == VB2_SUCCESS)
+ rv = call_rv;
+ break;
+ }
+
+ return rv;
}
vb2_error_t VbSelectAndLoadKernel(struct vb2_context *ctx,
VbSharedDataHeader *shared,
VbSelectAndLoadKernelParams *kparams)
{
- vb2_error_t rv = vb2_kernel_setup(ctx, shared, kparams);
+ vb2_error_t rv, call_rv;
+
+ rv = vb2_kernel_setup(ctx, shared, kparams);
if (rv)
goto VbSelectAndLoadKernel_exit;
@@ -441,10 +488,18 @@ vb2_error_t VbSelectAndLoadKernel(struct vb2_context *ctx,
VbSelectAndLoadKernel_exit:
- if (VB2_SUCCESS == rv)
- rv = vb2_kernel_phase4(ctx, kparams);
+ if (rv == VB2_SUCCESS)
+ vb2_kernel_fill_kparams(ctx, kparams);
+
+ /* Commit data, but retain any previous errors */
+ call_rv = vb2_commit_data(ctx);
+ if (rv == VB2_SUCCESS)
+ rv = call_rv;
- vb2_kernel_cleanup(ctx);
+ /* Lock secdata_kernel, but retain any previous errors */
+ call_rv = vb2_secdata_kernel_lock(ctx);
+ if (rv == VB2_SUCCESS)
+ rv = call_rv;
/* Pass through return value from boot path */
VB2_DEBUG("Returning %#x\n", rv);