From d7da706484823654f4f7f50b8d30f4d7a9d61089 Mon Sep 17 00:00:00 2001 From: Dan Ehrenberg Date: Wed, 22 Apr 2015 11:00:51 -0700 Subject: cgpt: Handle read errors gracefully When a read fails in getting the GPT, just zero the contents of the buffer and carry on. Some testing changes are required for this. When a read of the GPT fails, it is no longer fatal, so tests of that have been adjusted. Tests have been improved to show that the GPT is automatically repaired when a read error occurs. There was one test which checked that a zero-sized disk would fail to load a kernel, but it was surrounded by a number of mocked functions which normally do that error checking, and it amounted to the same test as read failure; that test was deleted. BUG=chrome-os-partner:35440 TEST=vboot tests pass BRANCH=none Change-Id: I0c05813e7492920433733947d3fb74a7e4aa66f2 Signed-off-by: Dan Ehrenberg Reviewed-on: https://chromium-review.googlesource.com/266882 Reviewed-by: Randall Spangler --- firmware/lib/gpt_misc.c | 24 +++++++++++++------- tests/vboot_kernel_tests.c | 56 ++++++++++++++++++++++++++++------------------ 2 files changed, 50 insertions(+), 30 deletions(-) diff --git a/firmware/lib/gpt_misc.c b/firmware/lib/gpt_misc.c index 4061bdd9..cff9221f 100644 --- a/firmware/lib/gpt_misc.c +++ b/firmware/lib/gpt_misc.c @@ -43,8 +43,10 @@ int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData *gptdata) return 1; /* Read primary header from the drive, skipping the protective MBR */ - if (0 != VbExDiskRead(disk_handle, 1, 1, gptdata->primary_header)) - return 1; + if (0 != VbExDiskRead(disk_handle, 1, 1, gptdata->primary_header)) { + VBDEBUG(("Read error in primary GPT header\n")); + Memset(gptdata->primary_header, 0, gptdata->sector_bytes); + } /* Only read primary GPT if the primary header is valid */ GptHeader* primary_header = (GptHeader*)gptdata->primary_header; @@ -60,16 +62,20 @@ int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData *gptdata) if (0 != VbExDiskRead(disk_handle, primary_header->entries_lba, entries_sectors, - gptdata->primary_entries)) - return 1; + gptdata->primary_entries)) { + VBDEBUG(("Read error in primary GPT entries\n")); + primary_valid = 0; + } } else { VBDEBUG(("Primary GPT header invalid!\n")); } /* Read secondary header from the end of the drive */ if (0 != VbExDiskRead(disk_handle, gptdata->gpt_drive_sectors - 1, 1, - gptdata->secondary_header)) - return 1; + gptdata->secondary_header)) { + VBDEBUG(("Read error in secondary GPT header\n")); + Memset(gptdata->secondary_header, 0, gptdata->sector_bytes); + } /* Only read secondary GPT if the secondary header is valid */ GptHeader* secondary_header = (GptHeader*)gptdata->secondary_header; @@ -85,8 +91,10 @@ int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData *gptdata) if (0 != VbExDiskRead(disk_handle, secondary_header->entries_lba, entries_sectors, - gptdata->secondary_entries)) - return 1; + gptdata->secondary_entries)) { + VBDEBUG(("Read error in secondary GPT entries\n")); + secondary_valid = 0; + } } else { VBDEBUG(("Secondary GPT header invalid!\n")); } diff --git a/tests/vboot_kernel_tests.c b/tests/vboot_kernel_tests.c index 03e77f98..e690bc31 100644 --- a/tests/vboot_kernel_tests.c +++ b/tests/vboot_kernel_tests.c @@ -12,6 +12,7 @@ #include "cgptlib.h" #include "cgptlib_internal.h" +#include "crc32.h" #include "gbb_header.h" #include "gpt.h" #include "host_common.h" @@ -467,27 +468,43 @@ static void ReadWriteGptTest(void) /* Error reading */ ResetMocks(); disk_read_to_fail = 1; - TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail"); - Memset(g.primary_header, '\0', g.sector_bytes); - WriteAndFreeGptData(handle, &g); + 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_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail"); - Memset(g.primary_header, '\0', g.sector_bytes); - WriteAndFreeGptData(handle, &g); + 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_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail"); - Memset(g.primary_header, '\0', g.sector_bytes); - WriteAndFreeGptData(handle, &g); + 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_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail"); - Memset(g.primary_header, '\0', g.sector_bytes); - WriteAndFreeGptData(handle, &g); + 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(); @@ -542,21 +559,11 @@ static void InvalidParamsTest(void) TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_PARAMETER, "Huge lba size"); - ResetMocks(); - disk_read_to_fail = 1; - TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_NO_KERNEL_FOUND, - "Can't read disk"); - ResetMocks(); gpt_init_fail = 1; TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_NO_KERNEL_FOUND, "Bad GPT"); - ResetMocks(); - lkp.gpt_lba_count = 0; - TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_NO_KERNEL_FOUND, - "GPT size = 0"); - /* This causes the stream open call to fail */ ResetMocks(); lkp.disk_handle = NULL; @@ -765,6 +772,11 @@ static void LoadKernelTest(void) lkp.boot_flags |= BOOT_FLAG_EXTERNAL_GPT; TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Succeed external GPT"); TEST_EQ(gpt_flag_external, 1, "GPT was external"); + + /* Check recovery from unreadble primary GPT */ + ResetMocks(); + disk_read_to_fail = 1; + TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Can't read disk"); } int main(void) -- cgit v1.2.1