Files
OpenCellular/tests/vb2_secdata_tests.c
Julius Werner b550fb1804 vboot2: Fail vb2_secdata_(get|set) when secdata was not initialized
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
2015-02-04 22:01:18 +00:00

116 lines
3.6 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.
*
* Tests for firmware secure storage library.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "test_common.h"
#include "vboot_common.h"
#include "2common.h"
#include "2api.h"
#include "2misc.h"
#include "2secdata.h"
static void test_changed(struct vb2_context *ctx, int changed, const char *why)
{
if (changed)
TEST_NEQ(ctx->flags & VB2_CONTEXT_SECDATA_CHANGED, 0, why);
else
TEST_EQ(ctx->flags & VB2_CONTEXT_SECDATA_CHANGED, 0, why);
ctx->flags &= ~VB2_CONTEXT_SECDATA_CHANGED;
};
static void secdata_test(void)
{
uint8_t workbuf[VB2_WORKBUF_RECOMMENDED_SIZE]
__attribute__ ((aligned (VB2_WORKBUF_ALIGN)));
struct vb2_context c = {
.flags = 0,
.workbuf = workbuf,
.workbuf_size = sizeof(workbuf),
};
uint32_t v = 1;
/* Blank data is invalid */
memset(c.secdata, 0xa6, sizeof(c.secdata));
TEST_EQ(vb2_secdata_check_crc(&c),
VB2_ERROR_SECDATA_CRC, "Check blank CRC");
TEST_EQ(vb2_secdata_init(&c),
VB2_ERROR_SECDATA_CRC, "Init blank CRC");
/* Create good data */
TEST_SUCC(vb2_secdata_create(&c), "Create");
TEST_SUCC(vb2_secdata_check_crc(&c), "Check created CRC");
TEST_SUCC(vb2_secdata_init(&c), "Init created CRC");
test_changed(&c, 1, "Create changes data");
/* Now corrupt it */
c.secdata[2]++;
TEST_EQ(vb2_secdata_check_crc(&c),
VB2_ERROR_SECDATA_CRC, "Check invalid CRC");
TEST_EQ(vb2_secdata_init(&c),
VB2_ERROR_SECDATA_CRC, "Init invalid CRC");
vb2_secdata_create(&c);
c.flags = 0;
/* Read/write flags */
TEST_SUCC(vb2_secdata_get(&c, VB2_SECDATA_FLAGS, &v), "Get flags");
TEST_EQ(v, 0, "Flags created 0");
test_changed(&c, 0, "Get doesn't change data");
TEST_SUCC(vb2_secdata_set(&c, VB2_SECDATA_FLAGS, 0x12), "Set flags");
test_changed(&c, 1, "Set changes data");
TEST_SUCC(vb2_secdata_set(&c, VB2_SECDATA_FLAGS, 0x12), "Set flags 2");
test_changed(&c, 0, "Set again doesn't change data");
TEST_SUCC(vb2_secdata_get(&c, VB2_SECDATA_FLAGS, &v), "Get flags 2");
TEST_EQ(v, 0x12, "Flags changed");
TEST_EQ(vb2_secdata_set(&c, VB2_SECDATA_FLAGS, 0x100),
VB2_ERROR_SECDATA_SET_FLAGS, "Bad flags");
/* Read/write versions */
TEST_SUCC(vb2_secdata_get(&c, VB2_SECDATA_VERSIONS, &v),
"Get versions");
TEST_EQ(v, 0, "Versions created 0");
test_changed(&c, 0, "Get doesn't change data");
TEST_SUCC(vb2_secdata_set(&c, VB2_SECDATA_VERSIONS, 0x123456ff),
"Set versions");
test_changed(&c, 1, "Set changes data");
TEST_SUCC(vb2_secdata_set(&c, VB2_SECDATA_VERSIONS, 0x123456ff),
"Set versions 2");
test_changed(&c, 0, "Set again doesn't change data");
TEST_SUCC(vb2_secdata_get(&c, VB2_SECDATA_VERSIONS, &v),
"Get versions 2");
TEST_EQ(v, 0x123456ff, "Versions changed");
/* Invalid field fails */
TEST_EQ(vb2_secdata_get(&c, -1, &v),
VB2_ERROR_SECDATA_GET_PARAM, "Get invalid");
TEST_EQ(vb2_secdata_set(&c, -1, 456),
VB2_ERROR_SECDATA_SET_PARAM, "Set invalid");
test_changed(&c, 0, "Set invalid field doesn't change data");
/* Read/write uninitialized data fails */
vb2_get_sd(&c)->status &= ~VB2_SD_STATUS_SECDATA_INIT;
TEST_EQ(vb2_secdata_get(&c, VB2_SECDATA_VERSIONS, &v),
VB2_ERROR_SECDATA_GET_UNINITIALIZED, "Get uninitialized");
test_changed(&c, 0, "Get uninitialized doesn't change data");
TEST_EQ(vb2_secdata_set(&c, VB2_SECDATA_VERSIONS, 0x123456ff),
VB2_ERROR_SECDATA_SET_UNINITIALIZED, "Set uninitialized");
test_changed(&c, 0, "Set uninitialized doesn't change data");
}
int main(int argc, char* argv[])
{
secdata_test();
return gTestSuccess ? 0 : 255;
}