diff --git a/block/partitions/efi.c b/block/partitions/efi.c index e3cb4f19cf6d6b3d79d651c3e13e8ff4e1538fbb..b028af688361c3abc336685d146740e2a887787c 100644 --- a/block/partitions/efi.c +++ b/block/partitions/efi.c @@ -166,6 +166,7 @@ static inline int pmbr_part_valid(gpt_mbr_record *part) /** * is_pmbr_valid(): test Protective MBR for validity * @mbr: pointer to a legacy mbr structure + * @total_sectors: amount of sectors in the device * * Description: Checks for a valid protective or hybrid * master boot record (MBR). The validity of a pMBR depends @@ -180,9 +181,9 @@ static inline int pmbr_part_valid(gpt_mbr_record *part) * Returns 0 upon invalid MBR, or GPT_MBR_PROTECTIVE or * GPT_MBR_HYBRID depending on the device layout. */ -static int is_pmbr_valid(legacy_mbr *mbr) +static int is_pmbr_valid(legacy_mbr *mbr, sector_t total_sectors) { - int i, ret = 0; /* invalid by default */ + int i, part = 0, ret = 0; /* invalid by default */ if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE) goto done; @@ -190,6 +191,7 @@ static int is_pmbr_valid(legacy_mbr *mbr) for (i = 0; i < 4; i++) { ret = pmbr_part_valid(&mbr->partition_record[i]); if (ret == GPT_MBR_PROTECTIVE) { + part = i; /* * Ok, we at least know that there's a protective MBR, * now check if there are other partition types for @@ -207,6 +209,18 @@ static int is_pmbr_valid(legacy_mbr *mbr) EFI_PMBR_OSTYPE_EFI_GPT) && (mbr->partition_record[i].os_type != 0x00)) ret = GPT_MBR_HYBRID; + + /* + * Protective MBRs take up the lesser of the whole disk + * or 2 TiB (32bit LBA), ignoring the rest of the disk. + * + * Hybrid MBRs do not necessarily comply with this. + */ + if (ret == GPT_MBR_PROTECTIVE) { + if (le32_to_cpu(mbr->partition_record[part].size_in_lba) != + min((uint32_t) total_sectors - 1, 0xFFFFFFFF)) + ret = 0; + } done: return ret; } @@ -568,6 +582,7 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, gpt_header *pgpt = NULL, *agpt = NULL; gpt_entry *pptes = NULL, *aptes = NULL; legacy_mbr *legacymbr; + sector_t total_sectors = i_size_read(state->bdev->bd_inode) >> 9; u64 lastlba; if (!ptes) @@ -581,7 +596,7 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, goto fail; read_lba(state, 0, (u8 *)legacymbr, sizeof(*legacymbr)); - good_pmbr = is_pmbr_valid(legacymbr); + good_pmbr = is_pmbr_valid(legacymbr, total_sectors); kfree(legacymbr); if (!good_pmbr)