mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-25 02:35:22 +00:00
This patch adds a check to vboot2 secdata accessor functions that returns an error if vb2_secdata_init() has not yet been called or failed for some reason. This avoids a problem where vboot may misinterpret random garbage (e.g. from transient read failures) as valid secdata in recovery mode and write it back to the TPM (bricking the device in a way that requires manual repair). Also removes VB2_ERROR_SECDATA_VERSION check. This check was not terribly useful since there should be no way a vboot2 device could ever have secdata version 1 (and if it did, it should still fail CRC checks). This error can trigger for cases when secdata contains random garbage (e.g. all zeroes) and prevent the much more appropriate VB2_ERROR_SECDATA_CRC error from even being checked for, which just creates confusion and makes it harder to determine the real problem. BRANCH=veyron BUG=chrome-os-partner:34871 TEST=Emulated TPM read errors by just manually memset()ing secdata to 0 in coreboot, verified that vboot does not write back to the TPM and the device will start working fine again once the disruption is removed. Change-Id: I76bcbdbcd8106a0d34717cc91a8f2d7cda303c3f Signed-off-by: Julius Werner <jwerner@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/244846
123 lines
2.8 KiB
C
123 lines
2.8 KiB
C
/* Copyright (c) 2014 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.
|
|
*
|
|
* Secure storage APIs
|
|
*/
|
|
|
|
#include "2sysincludes.h"
|
|
#include "2common.h"
|
|
#include "2crc8.h"
|
|
#include "2misc.h"
|
|
#include "2secdata.h"
|
|
|
|
int vb2_secdata_check_crc(const struct vb2_context *ctx)
|
|
{
|
|
const struct vb2_secdata *sec =
|
|
(const struct vb2_secdata *)ctx->secdata;
|
|
|
|
/* Verify CRC */
|
|
if (sec->crc8 != vb2_crc8(sec, offsetof(struct vb2_secdata, crc8)))
|
|
return VB2_ERROR_SECDATA_CRC;
|
|
|
|
return VB2_SUCCESS;
|
|
}
|
|
|
|
int vb2_secdata_create(struct vb2_context *ctx)
|
|
{
|
|
struct vb2_secdata *sec = (struct vb2_secdata *)ctx->secdata;
|
|
|
|
/* Clear the entire struct */
|
|
memset(sec, 0, sizeof(*sec));
|
|
|
|
/* Set to current version */
|
|
sec->struct_version = VB2_SECDATA_VERSION;
|
|
|
|
/* Calculate initial CRC */
|
|
sec->crc8 = vb2_crc8(sec, offsetof(struct vb2_secdata, crc8));
|
|
ctx->flags |= VB2_CONTEXT_SECDATA_CHANGED;
|
|
return VB2_SUCCESS;
|
|
}
|
|
|
|
int vb2_secdata_init(struct vb2_context *ctx)
|
|
{
|
|
struct vb2_shared_data *sd = vb2_get_sd(ctx);
|
|
int rv;
|
|
|
|
rv = vb2_secdata_check_crc(ctx);
|
|
if (rv)
|
|
return rv;
|
|
|
|
/* Set status flag */
|
|
sd->status |= VB2_SD_STATUS_SECDATA_INIT;
|
|
// TODO: unit test for that
|
|
|
|
/* Read this now to make sure crossystem has it even in rec mode. */
|
|
rv = vb2_secdata_get(ctx, VB2_SECDATA_VERSIONS,
|
|
&sd->fw_version_secdata);
|
|
if (rv)
|
|
return rv;
|
|
|
|
return VB2_SUCCESS;
|
|
}
|
|
|
|
int vb2_secdata_get(struct vb2_context *ctx,
|
|
enum vb2_secdata_param param,
|
|
uint32_t *dest)
|
|
{
|
|
struct vb2_secdata *sec = (struct vb2_secdata *)ctx->secdata;
|
|
|
|
if (!(vb2_get_sd(ctx)->status & VB2_SD_STATUS_SECDATA_INIT))
|
|
return VB2_ERROR_SECDATA_GET_UNINITIALIZED;
|
|
|
|
switch(param) {
|
|
case VB2_SECDATA_FLAGS:
|
|
*dest = sec->flags;
|
|
return VB2_SUCCESS;
|
|
|
|
case VB2_SECDATA_VERSIONS:
|
|
*dest = sec->fw_versions;
|
|
return VB2_SUCCESS;
|
|
|
|
default:
|
|
return VB2_ERROR_SECDATA_GET_PARAM;
|
|
}
|
|
}
|
|
|
|
int vb2_secdata_set(struct vb2_context *ctx,
|
|
enum vb2_secdata_param param,
|
|
uint32_t value)
|
|
{
|
|
struct vb2_secdata *sec = (struct vb2_secdata *)ctx->secdata;
|
|
uint32_t now;
|
|
|
|
if (!(vb2_get_sd(ctx)->status & VB2_SD_STATUS_SECDATA_INIT))
|
|
return VB2_ERROR_SECDATA_SET_UNINITIALIZED;
|
|
|
|
/* If not changing the value, don't regenerate the CRC. */
|
|
if (vb2_secdata_get(ctx, param, &now) == VB2_SUCCESS && now == value)
|
|
return VB2_SUCCESS;
|
|
|
|
switch(param) {
|
|
case VB2_SECDATA_FLAGS:
|
|
/* Make sure flags is in valid range */
|
|
if (value > 0xff)
|
|
return VB2_ERROR_SECDATA_SET_FLAGS;
|
|
|
|
sec->flags = value;
|
|
break;
|
|
|
|
case VB2_SECDATA_VERSIONS:
|
|
sec->fw_versions = value;
|
|
break;
|
|
|
|
default:
|
|
return VB2_ERROR_SECDATA_SET_PARAM;
|
|
}
|
|
|
|
/* Regenerate CRC */
|
|
sec->crc8 = vb2_crc8(sec, offsetof(struct vb2_secdata, crc8));
|
|
ctx->flags |= VB2_CONTEXT_SECDATA_CHANGED;
|
|
return VB2_SUCCESS;
|
|
}
|