summaryrefslogtreecommitdiff
path: root/tests/gpt_misc_tests.c
diff options
context:
space:
mode:
authorJoel Kitching <kitching@google.com>2021-07-20 07:18:42 +0800
committerCommit Bot <commit-bot@chromium.org>2021-07-21 06:49:54 +0000
commite355c9ea7e30775dc9698646339a4d9fe5fe3ee1 (patch)
treea0ddc6809fc90f14a9971fd587bb76c4eda7079b /tests/gpt_misc_tests.c
parent2d3af1227d6c74733f4e16da424ffaabdfcd23d4 (diff)
downloadvboot-e355c9ea7e30775dc9698646339a4d9fe5fe3ee1.tar.gz
vboot/vboot_kernel: split gpt tests out of vboot_kernel_tests
These don't really belong together. We can get two cleaner test files by splitting them apart. This CL is part of a series to merge vboot1 and vboot2.0 kernel verification code; see b/181739551. BUG=b:181739551, b:172337800, b:124141368 TEST=make clean && make runtests BRANCH=none Signed-off-by: Joel Kitching <kitching@google.com> Change-Id: Idaa4c36214cc98bffdc50bdb5c071673829250ee Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/3039164 Tested-by: Joel Kitching <kitching@chromium.org> Reviewed-by: Julius Werner <jwerner@chromium.org> Commit-Queue: Joel Kitching <kitching@chromium.org>
Diffstat (limited to 'tests/gpt_misc_tests.c')
-rw-r--r--tests/gpt_misc_tests.c378
1 files changed, 378 insertions, 0 deletions
diff --git a/tests/gpt_misc_tests.c b/tests/gpt_misc_tests.c
new file mode 100644
index 00000000..e0a8d56e
--- /dev/null
+++ b/tests/gpt_misc_tests.c
@@ -0,0 +1,378 @@
+/* Copyright (c) 2013 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 vboot_kernel.c
+ */
+
+#include "2api.h"
+#include "cgptlib.h"
+#include "cgptlib_internal.h"
+#include "gpt.h"
+#include "test_common.h"
+
+#define LOGCALL(fmt, args...) sprintf(call_log + strlen(call_log), fmt, ##args)
+#define TEST_CALLS(expect_log) TEST_STR_EQ(call_log, expect_log, " calls")
+
+/* Assumes 512-byte disk sectors */
+#define MOCK_SECTOR_SIZE 512
+#define MOCK_SECTOR_COUNT 1024
+
+/* Mock kernel partition */
+struct mock_part {
+ uint32_t start;
+ uint32_t size;
+};
+
+/* Mock data */
+static char call_log[4096];
+static int disk_read_to_fail;
+static int disk_write_to_fail;
+
+static VbExDiskHandle_t handle;
+static uint8_t mock_disk[MOCK_SECTOR_SIZE * MOCK_SECTOR_COUNT];
+static GptHeader *mock_gpt_primary =
+ (GptHeader*)&mock_disk[MOCK_SECTOR_SIZE * 1];
+static GptHeader *mock_gpt_secondary =
+ (GptHeader*)&mock_disk[MOCK_SECTOR_SIZE * (MOCK_SECTOR_COUNT - 1)];
+
+/**
+ * Prepare a valid GPT header that will pass CheckHeader() tests
+ */
+static void SetupGptHeader(GptHeader *h, int is_secondary)
+{
+ memset(h, '\0', MOCK_SECTOR_SIZE);
+
+ /* "EFI PART" */
+ memcpy(h->signature, GPT_HEADER_SIGNATURE, GPT_HEADER_SIGNATURE_SIZE);
+ h->revision = GPT_HEADER_REVISION;
+ h->size = MIN_SIZE_OF_HEADER;
+
+ /* 16KB: 128 entries of 128 bytes */
+ h->size_of_entry = sizeof(GptEntry);
+ h->number_of_entries = MAX_NUMBER_OF_ENTRIES;
+
+ /* Set LBA pointers for primary or secondary header */
+ if (is_secondary) {
+ h->my_lba = MOCK_SECTOR_COUNT - GPT_HEADER_SECTORS;
+ h->entries_lba = h->my_lba - CalculateEntriesSectors(h,
+ MOCK_SECTOR_SIZE);
+ } else {
+ h->my_lba = GPT_PMBR_SECTORS;
+ h->entries_lba = h->my_lba + 1;
+ }
+
+ h->first_usable_lba = 2 + CalculateEntriesSectors(h, MOCK_SECTOR_SIZE);
+ h->last_usable_lba = MOCK_SECTOR_COUNT - 2 - CalculateEntriesSectors(h,
+ MOCK_SECTOR_SIZE);
+
+ h->header_crc32 = HeaderCrc(h);
+}
+
+static void ResetCallLog(void)
+{
+ *call_log = 0;
+}
+
+/**
+ * Reset mock data (for use before each test)
+ */
+static void ResetMocks(void)
+{
+ ResetCallLog();
+
+ memset(&mock_disk, 0, sizeof(mock_disk));
+ SetupGptHeader(mock_gpt_primary, 0);
+ SetupGptHeader(mock_gpt_secondary, 1);
+
+ disk_read_to_fail = -1;
+ disk_write_to_fail = -1;
+}
+
+/* Mocks */
+
+vb2_error_t VbExDiskRead(VbExDiskHandle_t h, uint64_t lba_start,
+ uint64_t lba_count, void *buffer)
+{
+ LOGCALL("VbExDiskRead(h, %d, %d)\n", (int)lba_start, (int)lba_count);
+
+ if ((int)lba_start == disk_read_to_fail)
+ return VB2_ERROR_MOCK;
+
+ memcpy(buffer, &mock_disk[lba_start * MOCK_SECTOR_SIZE],
+ lba_count * MOCK_SECTOR_SIZE);
+
+ return VB2_SUCCESS;
+}
+
+vb2_error_t VbExDiskWrite(VbExDiskHandle_t h, uint64_t lba_start,
+ uint64_t lba_count, const void *buffer)
+{
+ LOGCALL("VbExDiskWrite(h, %d, %d)\n", (int)lba_start, (int)lba_count);
+
+ if ((int)lba_start == disk_write_to_fail)
+ return VB2_ERROR_MOCK;
+
+ memcpy(&mock_disk[lba_start * MOCK_SECTOR_SIZE], buffer,
+ lba_count * MOCK_SECTOR_SIZE);
+
+ return VB2_SUCCESS;
+}
+
+/**
+ * Test reading/writing GPT
+ */
+static void ReadWriteGptTest(void)
+{
+ GptData g;
+ GptHeader *h;
+
+ g.sector_bytes = MOCK_SECTOR_SIZE;
+ g.streaming_drive_sectors = g.gpt_drive_sectors = MOCK_SECTOR_COUNT;
+ g.valid_headers = g.valid_entries = MASK_BOTH;
+
+ ResetMocks();
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead");
+ TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
+ "VbExDiskRead(h, 2, 32)\n"
+ "VbExDiskRead(h, 1023, 1)\n"
+ "VbExDiskRead(h, 991, 32)\n");
+ ResetCallLog();
+ /*
+ * Valgrind complains about access to uninitialized memory here, so
+ * zero the primary header before each test.
+ */
+ memset(g.primary_header, '\0', g.sector_bytes);
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree");
+ TEST_CALLS("");
+
+ /*
+ * Invalidate primary GPT header,
+ * check that AllocAndReadGptData still succeeds
+ */
+ ResetMocks();
+ memset(mock_gpt_primary, '\0', sizeof(*mock_gpt_primary));
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0,
+ "AllocAndRead primary invalid");
+ TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 1, "Primary header is invalid");
+ TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 0, "Secondary header is valid");
+ TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
+ "VbExDiskRead(h, 1023, 1)\n"
+ "VbExDiskRead(h, 991, 32)\n");
+ WriteAndFreeGptData(handle, &g);
+
+ /*
+ * Invalidate secondary GPT header,
+ * check that AllocAndReadGptData still succeeds
+ */
+ ResetMocks();
+ memset(mock_gpt_secondary, '\0', sizeof(*mock_gpt_secondary));
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0,
+ "AllocAndRead secondary invalid");
+ TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 0, "Primary header is valid");
+ TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 1, "Secondary header is invalid");
+ TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
+ "VbExDiskRead(h, 2, 32)\n"
+ "VbExDiskRead(h, 1023, 1)\n");
+ WriteAndFreeGptData(handle, &g);
+
+ /*
+ * Invalidate primary AND secondary GPT header,
+ * check that AllocAndReadGptData fails.
+ */
+ ResetMocks();
+ memset(mock_gpt_primary, '\0', sizeof(*mock_gpt_primary));
+ memset(mock_gpt_secondary, '\0', sizeof(*mock_gpt_secondary));
+ TEST_EQ(AllocAndReadGptData(handle, &g), 1,
+ "AllocAndRead primary and secondary invalid");
+ TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 1, "Primary header is invalid");
+ TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 1, "Secondary header is invalid");
+ TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
+ "VbExDiskRead(h, 1023, 1)\n");
+ WriteAndFreeGptData(handle, &g);
+
+ /*
+ * Invalidate primary GPT header and check that it is
+ * repaired by GptRepair().
+ *
+ * This would normally be called by LoadKernel()->GptInit()
+ * but this callback is mocked in these tests.
+ */
+ ResetMocks();
+ memset(mock_gpt_primary, '\0', sizeof(*mock_gpt_primary));
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0,
+ "Fix Primary GPT: AllocAndRead");
+ /* Call GptRepair() with input indicating secondary GPT is valid */
+ g.valid_headers = g.valid_entries = MASK_SECONDARY;
+ GptRepair(&g);
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0,
+ "Fix Primary GPT: WriteAndFreeGptData");
+ TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
+ "VbExDiskRead(h, 1023, 1)\n"
+ "VbExDiskRead(h, 991, 32)\n"
+ "VbExDiskWrite(h, 1, 1)\n"
+ "VbExDiskWrite(h, 2, 32)\n");
+ TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 0, "Fix Primary GPT: Primary header is valid");
+
+ /*
+ * Invalidate secondary GPT header and check that it can be
+ * repaired by GptRepair().
+ *
+ * This would normally be called by LoadKernel()->GptInit()
+ * but this callback is mocked in these tests.
+ */
+ ResetMocks();
+ memset(mock_gpt_secondary, '\0', sizeof(*mock_gpt_secondary));
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0,
+ "Fix Secondary GPT: AllocAndRead");
+ /* Call GptRepair() with input indicating primary GPT is valid */
+ g.valid_headers = g.valid_entries = MASK_PRIMARY;
+ GptRepair(&g);
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0,
+ "Fix Secondary GPT: WriteAndFreeGptData");
+ TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
+ "VbExDiskRead(h, 2, 32)\n"
+ "VbExDiskRead(h, 1023, 1)\n"
+ "VbExDiskWrite(h, 1023, 1)\n"
+ "VbExDiskWrite(h, 991, 32)\n");
+ TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 0, "Fix Secondary GPT: Secondary header is valid");
+
+ /* Data which is changed is written */
+ ResetMocks();
+ AllocAndReadGptData(handle, &g);
+ g.modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1;
+ ResetCallLog();
+ memset(g.primary_header, '\0', g.sector_bytes);
+ h = (GptHeader*)g.primary_header;
+ h->entries_lba = 2;
+ h->number_of_entries = MAX_NUMBER_OF_ENTRIES;
+ h->size_of_entry = sizeof(GptEntry);
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
+ TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
+ "VbExDiskWrite(h, 2, 32)\n");
+
+ /* Data which is changed is written */
+ ResetMocks();
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ ResetCallLog();
+ memset(g.primary_header, '\0', g.sector_bytes);
+ h = (GptHeader*)g.primary_header;
+ h->entries_lba = 2;
+ h->number_of_entries = MAX_NUMBER_OF_ENTRIES;
+ h->size_of_entry = sizeof(GptEntry);
+ h = (GptHeader*)g.secondary_header;
+ h->entries_lba = 991;
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all");
+ TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
+ "VbExDiskWrite(h, 2, 32)\n"
+ "VbExDiskWrite(h, 1023, 1)\n"
+ "VbExDiskWrite(h, 991, 32)\n");
+
+ /* If legacy signature, don't modify GPT header/entries 1 */
+ ResetMocks();
+ AllocAndReadGptData(handle, &g);
+ h = (GptHeader *)g.primary_header;
+ memcpy(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE);
+ g.modified = -1;
+ ResetCallLog();
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all");
+ TEST_CALLS("VbExDiskWrite(h, 1023, 1)\n"
+ "VbExDiskWrite(h, 991, 32)\n");
+
+ /* Error reading */
+ ResetMocks();
+ disk_read_to_fail = 1;
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
+ g.valid_headers = g.valid_entries = MASK_SECONDARY;
+ GptRepair(&g);
+ ResetCallLog();
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
+ TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
+ "VbExDiskWrite(h, 2, 32)\n");
+
+ ResetMocks();
+ disk_read_to_fail = 2;
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
+ g.valid_headers = MASK_BOTH;
+ g.valid_entries = MASK_SECONDARY;
+ GptRepair(&g);
+ ResetCallLog();
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
+ TEST_CALLS("VbExDiskWrite(h, 2, 32)\n");
+
+ ResetMocks();
+ disk_read_to_fail = 991;
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
+ g.valid_headers = MASK_BOTH;
+ g.valid_entries = MASK_PRIMARY;
+ GptRepair(&g);
+ ResetCallLog();
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 2");
+ TEST_CALLS("VbExDiskWrite(h, 991, 32)\n");
+
+ ResetMocks();
+ disk_read_to_fail = 1023;
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
+ g.valid_headers = g.valid_entries = MASK_PRIMARY;
+ GptRepair(&g);
+ ResetCallLog();
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 2");
+ TEST_CALLS("VbExDiskWrite(h, 1023, 1)\n"
+ "VbExDiskWrite(h, 991, 32)\n");
+
+ /* Error writing */
+ ResetMocks();
+ disk_write_to_fail = 1;
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ memset(g.primary_header, '\0', g.sector_bytes);
+ TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
+
+ ResetMocks();
+ disk_write_to_fail = 2;
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ memset(g.primary_header, '\0', g.sector_bytes);
+ h = (GptHeader*)g.primary_header;
+ h->entries_lba = 2;
+ TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
+
+ ResetMocks();
+ disk_write_to_fail = 991;
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ memset(g.primary_header, '\0', g.sector_bytes);
+ TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
+
+ ResetMocks();
+ disk_write_to_fail = 1023;
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ memset(g.primary_header, '\0', g.sector_bytes);
+ TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
+
+}
+
+int main(void)
+{
+ ReadWriteGptTest();
+
+ return gTestSuccess ? 0 : 255;
+}