From 5342b880f42bf6899eff352c83007b8f0e5fe69d Mon Sep 17 00:00:00 2001 From: Michael Marineau Date: Wed, 21 Sep 2016 15:29:55 -0700 Subject: [PATCH] gpt: read entries table at the same time as the header I personally think this reads easier. Also has the side effect of directly comparing the primary and backup tables instead of presuming they are equal if the crc32 matches. --- grub-core/lib/gpt.c | 69 +++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/grub-core/lib/gpt.c b/grub-core/lib/gpt.c index abc96dee0..1910e0a86 100644 --- a/grub-core/lib/gpt.c +++ b/grub-core/lib/gpt.c @@ -32,6 +32,11 @@ GRUB_MOD_LICENSE ("GPLv3+"); static grub_uint8_t grub_gpt_magic[] = GRUB_GPT_HEADER_MAGIC; +static grub_err_t +grub_gpt_read_entries (grub_disk_t disk, grub_gpt_t gpt, + struct grub_gpt_header *header, + void **ret_entries, + grub_size_t *ret_entries_size); char * grub_gpt_guid_to_str (grub_gpt_guid_t *guid) @@ -401,12 +406,21 @@ grub_gpt_read_primary (grub_disk_t disk, grub_gpt_t gpt) return grub_errno; gpt->status |= GRUB_GPT_PRIMARY_HEADER_VALID; + + if (grub_gpt_read_entries (disk, gpt, &gpt->primary, + &gpt->entries, &gpt->entries_size)) + return grub_errno; + + gpt->status |= GRUB_GPT_PRIMARY_ENTRIES_VALID; + return GRUB_ERR_NONE; } static grub_err_t grub_gpt_read_backup (grub_disk_t disk, grub_gpt_t gpt) { + void *entries = NULL; + grub_size_t entries_size; grub_uint64_t sector; grub_disk_addr_t addr; @@ -434,12 +448,35 @@ grub_gpt_read_backup (grub_disk_t disk, grub_gpt_t gpt) return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA"); gpt->status |= GRUB_GPT_BACKUP_HEADER_VALID; + + if (grub_gpt_read_entries (disk, gpt, &gpt->backup, + &entries, &entries_size)) + return grub_errno; + + if (gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID) + { + if (entries_size != gpt->entries_size || + grub_memcmp (entries, gpt->entries, entries_size) != 0) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "backup GPT out of sync"); + + grub_free (entries); + } + else + { + gpt->entries = entries; + gpt->entries_size = entries_size; + } + + gpt->status |= GRUB_GPT_BACKUP_ENTRIES_VALID; + return GRUB_ERR_NONE; } static grub_err_t grub_gpt_read_entries (grub_disk_t disk, grub_gpt_t gpt, - struct grub_gpt_header *header) + struct grub_gpt_header *header, + void **ret_entries, + grub_size_t *ret_entries_size) { void *entries = NULL; grub_uint32_t count, size, crc; @@ -481,9 +518,8 @@ grub_gpt_read_entries (grub_disk_t disk, grub_gpt_t gpt, goto fail; } - grub_free (gpt->entries); - gpt->entries = entries; - gpt->entries_size = entries_size; + *ret_entries = entries; + *ret_entries_size = entries_size; return GRUB_ERR_NONE; fail: @@ -522,30 +558,7 @@ grub_gpt_read (grub_disk_t disk) grub_gpt_read_backup (disk, gpt); /* If either succeeded clear any possible error from the other. */ - if (gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID || - gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) - grub_errno = GRUB_ERR_NONE; - else - goto fail; - - /* Similarly, favor the value or error from the primary table. */ - if (gpt->status & GRUB_GPT_BACKUP_HEADER_VALID && - !grub_gpt_read_entries (disk, gpt, &gpt->backup)) - { - grub_dprintf ("gpt", "read valid backup GPT from %s\n", disk->name); - gpt->status |= GRUB_GPT_BACKUP_ENTRIES_VALID; - } - - grub_errno = GRUB_ERR_NONE; - if (gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID && - !grub_gpt_read_entries (disk, gpt, &gpt->primary)) - { - grub_dprintf ("gpt", "read valid primary GPT from %s\n", disk->name); - gpt->status |= GRUB_GPT_PRIMARY_ENTRIES_VALID; - } - - if (gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID || - gpt->status & GRUB_GPT_BACKUP_ENTRIES_VALID) + if (grub_gpt_primary_valid (gpt) || grub_gpt_backup_valid (gpt)) grub_errno = GRUB_ERR_NONE; else goto fail;