summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2012-05-16 10:04:38 -0700
committerGerrit <chrome-bot@google.com>2012-05-17 09:21:50 -0700
commitfeac077c1d96d81f9c1c0b5253d0223b0a2d9448 (patch)
treebbc7c7346a37a9f78fd7d03e852a3df987ca180e /tests
parentf63ab219c5ee858a89ec0f33ad12536eff813bb2 (diff)
downloadvboot-feac077c1d96d81f9c1c0b5253d0223b0a2d9448.tar.gz
Add checksum to TPM RollbackSpace regions for FW and kernel.
BUG=chrome-os-partner:9707 TEST=manual make make runtests You can also test it by clearing the TPM, then manually looking at the TPM regions. In dev-mode, clear the regions and you'll see something like this: localhost ~ # tpmc read 1007 a 1 0 0 0 0 0 0 0 0 0 localhost ~ # tpmc read 1008 d 1 4c 57 52 47 0 0 0 0 0 0 0 0 localhost ~ # Go back to normal mode and reboot, and you'll see something like this: localhost ~ # tpmc read 1007 a 2 0 1 0 1 0 0 0 0 4f localhost ~ # tpmc read 1008 d 2 4c 57 52 47 1 0 1 0 0 0 0 55 localhost ~ # The important things are that the first number is now 2, instead of 1, and the last number is not zero (it's a checksum, so it'll vary depending on the other numbers, which will themselves vary according to the firmware and kernel versions). Change-Id: Ia4040311c2a4b2819792549b883377c8b6b89d48 Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/22856 Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/rollback_index2_tests.c254
-rwxr-xr-xtests/run_vboot_ec_tests.sh2
2 files changed, 246 insertions, 10 deletions
diff --git a/tests/rollback_index2_tests.c b/tests/rollback_index2_tests.c
index 7acb0989..1307ed08 100644
--- a/tests/rollback_index2_tests.c
+++ b/tests/rollback_index2_tests.c
@@ -11,6 +11,7 @@
#define _STUB_IMPLEMENTATION_ /* So we can use memset() ourselves */
+#include "crc8.h"
#include "rollback_index.h"
#include "test_common.h"
#include "tlcl.h"
@@ -38,6 +39,12 @@ static int mock_count = 0;
static int fail_at_count = 0;
static uint32_t fail_with_error = TPM_SUCCESS;
+/* Similar, to determine when to inject noise during reads & writes */
+#define MAX_NOISE_COUNT 64 /* no noise after this many */
+static int noise_count = 0; /* read/write attempt (zero-based) */
+static int noise_on[MAX_NOISE_COUNT]; /* calls to inject noise on */
+
+
/* Params / backing store for mocked Tlcl functions. */
static TPM_PERMANENT_FLAGS mock_pflags;
static RollbackSpaceFirmware mock_rsf;
@@ -51,6 +58,8 @@ static void ResetMocks(int fail_on_call, uint32_t fail_with_err) {
mock_count = 0;
fail_at_count = fail_on_call;
fail_with_error = fail_with_err;
+ noise_count = 0;
+ Memset(&noise_on, 0, sizeof(noise_on));
Memset(&mock_pflags, 0, sizeof(mock_pflags));
Memset(&mock_rsf, 0, sizeof(mock_rsf));
@@ -59,6 +68,16 @@ static void ResetMocks(int fail_on_call, uint32_t fail_with_err) {
}
/****************************************************************************/
+/* Function to garble data on its way to or from the TPM */
+static void MaybeInjectNoise(void* data, uint32_t length) {
+ if (noise_count < MAX_NOISE_COUNT && noise_on[noise_count]) {
+ uint8_t *val = data;
+ val[length-1]++;
+ }
+ noise_count++;
+}
+
+/****************************************************************************/
/* Mocks for tlcl functions which log the calls made to mock_calls[]. */
uint32_t TlclLibInit(void) {
@@ -97,9 +116,11 @@ uint32_t TlclRead(uint32_t index, void* data, uint32_t length) {
if (FIRMWARE_NV_INDEX == index) {
TEST_EQ(length, sizeof(mock_rsf), "TlclRead rsf size");
Memcpy(data, &mock_rsf, length);
+ MaybeInjectNoise(data, length);
} else if (KERNEL_NV_INDEX == index) {
TEST_EQ(length, sizeof(mock_rsk), "TlclRead rsk size");
Memcpy(data, &mock_rsk, length);
+ MaybeInjectNoise(data, length);
} else {
Memset(data, 0, length);
}
@@ -113,9 +134,11 @@ uint32_t TlclWrite(uint32_t index, const void* data, uint32_t length) {
if (FIRMWARE_NV_INDEX == index) {
TEST_EQ(length, sizeof(mock_rsf), "TlclWrite rsf size");
Memcpy(&mock_rsf, data, length);
+ MaybeInjectNoise(&mock_rsf, length);
} else if (KERNEL_NV_INDEX == index) {
TEST_EQ(length, sizeof(mock_rsk), "TlclWrite rsk size");
Memcpy(&mock_rsk, data, length);
+ MaybeInjectNoise(&mock_rsk, length);
}
return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
@@ -183,6 +206,204 @@ uint32_t TlclGetPermissions(uint32_t index, uint32_t* permissions) {
return (++mock_count == fail_at_count) ? fail_with_error : TPM_SUCCESS;
}
+
+/****************************************************************************/
+/* Tests for CRC errors */
+
+extern uint32_t ReadSpaceFirmware(RollbackSpaceFirmware* rsf);
+extern uint32_t WriteSpaceFirmware(RollbackSpaceFirmware* rsf);
+
+static void CrcTestFirmware(void) {
+ RollbackSpaceFirmware rsf;
+
+ /* noise on reading, shouldn't matter here because version == 0 */
+ ResetMocks(0, 0);
+ noise_on[0] = 1;
+ TEST_EQ(ReadSpaceFirmware(&rsf), 0, "ReadSpaceFirmware(), v0");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* But if the version >= 2, it will try three times and fail because the CRC
+ * is no good. */
+ ResetMocks(0, 0);
+ mock_rsf.struct_version = 2;
+ TEST_EQ(ReadSpaceFirmware(&rsf), TPM_E_CORRUPTED_STATE,
+ "ReadSpaceFirmware(), v2, bad CRC");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* OTOH, if the CRC is good and some noise happens, it should recover. */
+ ResetMocks(0, 0);
+ mock_rsf.struct_version = 2;
+ mock_rsf.crc8 = Crc8(&mock_rsf, offsetof(RollbackSpaceFirmware, crc8));
+ noise_on[0] = 1;
+ TEST_EQ(ReadSpaceFirmware(&rsf), 0, "ReadSpaceFirmware(), v2, good CRC");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* A write with version < 2 should convert to v2 and create the CRC */
+ ResetMocks(0, 0);
+ Memset(&rsf, 0, sizeof(rsf));
+ TEST_EQ(WriteSpaceFirmware(&rsf), 0, "WriteSpaceFirmware(), v0");
+ TEST_EQ(mock_rsf.struct_version, 2, "WriteSpaceFirmware(), check v2");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* Same as above, but with some noise during the readback */
+ ResetMocks(0, 0);
+ Memset(&rsf, 0, sizeof(rsf));
+ noise_on[1] = 1;
+ noise_on[2] = 1;
+ TEST_EQ(WriteSpaceFirmware(&rsf), 0, "WriteSpaceFirmware(), read noise");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* With noise during the write, we'll try the write again */
+ ResetMocks(0, 0);
+ Memset(&rsf, 0, sizeof(rsf));
+ noise_on[0] = 1;
+ TEST_EQ(WriteSpaceFirmware(&rsf), 0, "WriteSpaceFirmware(), write noise");
+ TEST_EQ(mock_rsf.struct_version, 2, "WriteSpaceFirmware(), check v2");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+
+ /* Only if it just keeps on failing forever do we eventually give up */
+ ResetMocks(0, 0);
+ Memset(&rsf, 0, sizeof(rsf));
+ Memset(noise_on, 1, sizeof(noise_on));
+ TEST_EQ(WriteSpaceFirmware(&rsf), TPM_E_CORRUPTED_STATE,
+ "WriteSpaceFirmware(), always noise");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
+ "tlcl calls");
+}
+
+extern uint32_t ReadSpaceKernel(RollbackSpaceKernel* rsk);
+extern uint32_t WriteSpaceKernel(RollbackSpaceKernel* rsk);
+
+static void CrcTestKernel(void) {
+ RollbackSpaceKernel rsk;
+
+ /* noise on reading, shouldn't matter here because version == 0 */
+ ResetMocks(0, 0);
+ noise_on[0] = 1;
+ TEST_EQ(ReadSpaceKernel(&rsk), 0, "ReadSpaceKernel(), v0");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+
+ /* But if the version >= 2, it will try three times and fail because the CRC
+ * is no good. */
+ ResetMocks(0, 0);
+ mock_rsk.struct_version = 2;
+ TEST_EQ(ReadSpaceKernel(&rsk), TPM_E_CORRUPTED_STATE,
+ "ReadSpaceKernel(), v2, bad CRC");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+
+ /* OTOH, if the CRC is good and some noise happens, it should recover. */
+ ResetMocks(0, 0);
+ mock_rsk.struct_version = 2;
+ mock_rsk.crc8 = Crc8(&mock_rsk, offsetof(RollbackSpaceKernel, crc8));
+ noise_on[0] = 1;
+ TEST_EQ(ReadSpaceKernel(&rsk), 0, "ReadSpaceKernel(), v2, good CRC");
+ TEST_STR_EQ(mock_calls,
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+
+ /* A write with version < 2 should convert to v2 and create the CRC */
+ ResetMocks(0, 0);
+ Memset(&rsk, 0, sizeof(rsk));
+ TEST_EQ(WriteSpaceKernel(&rsk), 0, "WriteSpaceKernel(), v0");
+ TEST_EQ(mock_rsk.struct_version, 2, "WriteSpaceKernel(), check v2");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+
+ /* Same as above, but with some noise during the readback */
+ ResetMocks(0, 0);
+ Memset(&rsk, 0, sizeof(rsk));
+ noise_on[1] = 1;
+ noise_on[2] = 1;
+ TEST_EQ(WriteSpaceKernel(&rsk), 0, "WriteSpaceKernel(), read noise");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+
+ /* With noise during the write, we'll try the write again */
+ ResetMocks(0, 0);
+ Memset(&rsk, 0, sizeof(rsk));
+ noise_on[0] = 1;
+ TEST_EQ(WriteSpaceKernel(&rsk), 0, "WriteSpaceKernel(), write noise");
+ TEST_EQ(mock_rsk.struct_version, 2, "WriteSpaceKernel(), check v2");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+
+ /* Only if it just keeps on failing forever do we eventually give up */
+ ResetMocks(0, 0);
+ Memset(&rsk, 0, sizeof(rsk));
+ Memset(noise_on, 1, sizeof(noise_on));
+ TEST_EQ(WriteSpaceKernel(&rsk), TPM_E_CORRUPTED_STATE,
+ "WriteSpaceKernel(), always noise");
+ TEST_STR_EQ(mock_calls,
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n",
+ "tlcl calls");
+}
+
/****************************************************************************/
/* Tests for misc helper functions */
@@ -265,9 +486,11 @@ static void OneTimeInitTest(void) {
/* kernel space */
"TlclDefineSpace(0x1008, 0x1, 13)\n"
"TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
/* firmware space */
"TlclDefineSpace(0x1007, 0x8001, 10)\n"
- "TlclWrite(0x1007, 10)\n",
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
"tlcl calls");
TEST_EQ(mock_rsf.struct_version, ROLLBACK_SPACE_FIRMWARE_VERSION, "rsf ver");
TEST_EQ(mock_rsf.flags, 0, "rsf flags");
@@ -290,9 +513,11 @@ static void OneTimeInitTest(void) {
/* kernel space */
"TlclDefineSpace(0x1008, 0x1, 13)\n"
"TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
/* firmware space */
"TlclDefineSpace(0x1007, 0x8001, 10)\n"
- "TlclWrite(0x1007, 10)\n",
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
"tlcl calls");
/* NV locking already initialized */
@@ -309,9 +534,11 @@ static void OneTimeInitTest(void) {
/* kernel space */
"TlclDefineSpace(0x1008, 0x1, 13)\n"
"TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
/* firmware space */
"TlclDefineSpace(0x1007, 0x8001, 10)\n"
- "TlclWrite(0x1007, 10)\n",
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
"tlcl calls");
/* Self test error */
@@ -397,8 +624,10 @@ static void SetupTpmTest(void) {
"TlclSetDeactivated(0)\n"
"TlclDefineSpace(0x1008, 0x1, 13)\n"
"TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n"
"TlclDefineSpace(0x1007, 0x8001, 10)\n"
- "TlclWrite(0x1007, 10)\n",
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
"tlcl calls");
/* Other firmware space error is passed through */
@@ -425,7 +654,8 @@ static void SetupTpmTest(void) {
"TlclForceClear()\n"
"TlclSetEnable()\n"
"TlclSetDeactivated(0)\n"
- "TlclWrite(0x1007, 10)\n",
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
"tlcl calls");
TEST_EQ(mock_rsf.flags, FLAG_LAST_BOOT_DEVELOPER, "fw space flags to dev");
@@ -441,7 +671,8 @@ static void SetupTpmTest(void) {
"TlclForceClear()\n"
"TlclSetEnable()\n"
"TlclSetDeactivated(0)\n"
- "TlclWrite(0x1007, 10)\n",
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
"tlcl calls");
TEST_EQ(mock_rsf.flags, 0, "fw space flags from dev");
@@ -492,7 +723,8 @@ static void RollbackFirmwareTest(void) {
"TlclForceClear()\n"
"TlclSetEnable()\n"
"TlclSetDeactivated(0)\n"
- "TlclWrite(0x1007, 10)\n",
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
"tlcl calls");
TEST_EQ(mock_rsf.flags, FLAG_LAST_BOOT_DEVELOPER, "fw space flags to dev");
@@ -502,7 +734,8 @@ static void RollbackFirmwareTest(void) {
TEST_EQ(mock_rsf.fw_versions, 0xBEAD1234, "RollbackFirmwareWrite() version");
TEST_STR_EQ(mock_calls,
"TlclRead(0x1007, 10)\n"
- "TlclWrite(0x1007, 10)\n",
+ "TlclWrite(0x1007, 10)\n"
+ "TlclRead(0x1007, 10)\n",
"tlcl calls");
ResetMocks(1, TPM_E_IOERROR);
@@ -573,7 +806,8 @@ static void RollbackKernelTest(void) {
"RollbackKernelWrite() version");
TEST_STR_EQ(mock_calls,
"TlclRead(0x1008, 13)\n"
- "TlclWrite(0x1008, 13)\n",
+ "TlclWrite(0x1008, 13)\n"
+ "TlclRead(0x1008, 13)\n",
"tlcl calls");
ResetMocks(1, TPM_E_IOERROR);
@@ -622,6 +856,8 @@ __pragma(warning (disable: 4100))
int main(int argc, char* argv[]) {
int error_code = 0;
+ CrcTestFirmware();
+ CrcTestKernel();
MiscTest();
OneTimeInitTest();
SetupTpmTest();
diff --git a/tests/run_vboot_ec_tests.sh b/tests/run_vboot_ec_tests.sh
index b5b0e7b1..302a3578 100755
--- a/tests/run_vboot_ec_tests.sh
+++ b/tests/run_vboot_ec_tests.sh
@@ -12,7 +12,7 @@
check_test_keys
for priv in ${TESTKEY_DIR}/*.vbprivk; do
- root=$(basename ${i%.vbprivk})
+ root=$(basename ${priv%.vbprivk})
pub="${priv%.vbprivk}.vbpubk"
echo "Trying $root ..."
${TEST_DIR}/vboot_ec_tests "$priv" "$pub"