From: Karel Zak Date: Thu, 22 Oct 2009 12:52:39 +0000 (+0200) Subject: libblkid: use BLKSSZGET for GPT sectors X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2a1dfbad1c3da1c98fa35e3175e84229253af387;p=util-linux libblkid: use BLKSSZGET for GPT sectors The current implementation uses fixed sector size (512 bytes), that's wrong. UEFI standard requires real logical sector size -- it means BLKSSZGET for Linux. The size of GPT header is not static, but whole sector is allocated for the header. In theory the HeaderSize field could be greater than sizeof(struct gpt_header). It means we have to read whole sector with the header, because the header crc32 checksum is counted according to HeaderSize. Signed-off-by: Karel Zak --- diff --git a/lib/blkdev.c b/lib/blkdev.c index 7c6c7bab..1ca4548b 100644 --- a/lib/blkdev.c +++ b/lib/blkdev.c @@ -85,7 +85,11 @@ blkdev_get_sectors(int fd, unsigned long long *sectors) return -1; } -/* get hardware sector size */ +/* get logical sector size (default is 512) + * + * This is the smallest unit the storage device can + * address. It is typically 512 bytes. + */ int blkdev_get_sector_size(int fd, int *sector_size) { diff --git a/shlibs/blkid/src/partitions/gpt.c b/shlibs/blkid/src/partitions/gpt.c index f2d54d74..dcadf754 100644 --- a/shlibs/blkid/src/partitions/gpt.c +++ b/shlibs/blkid/src/partitions/gpt.c @@ -23,7 +23,6 @@ #include "dos.h" #define GPT_PRIMARY_LBA 1 -#define GPT_BLOCK_SIZE 512 /* Signature - “EFI PART” */ #define GPT_HEADER_SIGNATURE 0x5452415020494645ULL @@ -67,7 +66,16 @@ struct gpt_header { uint32_t sizeof_partition_entry; uint32_t partition_entry_array_crc32; - uint8_t reserved2[GPT_BLOCK_SIZE - 92]; + /* + * The rest of the block is reserved by UEFI and must be zero. EFI + * standard handles this by: + * + * uint8_t reserved2[ BLKSSZGET - 92 ]; + * + * This definition is useless in practice. It is necessary to read + * whole block from the device rather than sizeof(struct gpt_header) + * only. + */ } __attribute__ ((packed)); /*** not used @@ -104,7 +112,7 @@ static inline unsigned char *get_lba_buffer(blkid_probe pr, uint64_t lba, size_t bytes) { return blkid_probe_get_buffer(pr, - GPT_BLOCK_SIZE * lba, bytes); + blkid_probe_get_sectorsize(pr) * lba, bytes); } static inline int guidcmp(efi_guid_t left, efi_guid_t right) @@ -115,7 +123,7 @@ static inline int guidcmp(efi_guid_t left, efi_guid_t right) static int last_lba(blkid_probe pr, uint64_t *lba) { blkid_loff_t sz = blkid_probe_get_size(pr); - if (sz < GPT_BLOCK_SIZE) + if (sz < blkid_probe_get_sectorsize(pr)) return -1; *lba = (sz >> 9) - 1; @@ -185,19 +193,31 @@ static struct gpt_header *get_gpt_header( uint32_t crc, orgcrc; uint64_t lu, fu; size_t esz; + uint32_t hsz, ssz; + + ssz = blkid_probe_get_sectorsize(pr); - h = (struct gpt_header *) get_lba_buffer(pr, lba, sizeof(*h)); + /* whole sector is allocated for GPT header */ + h = (struct gpt_header *) get_lba_buffer(pr, lba, ssz); if (!h) return NULL; if (le64_to_cpu(h->signature) != GPT_HEADER_SIGNATURE) return NULL; + hsz = le32_to_cpu(h->header_size); + + /* EFI: The HeaderSize must be greater than 92 and must be less + * than or equal to the logical block size. + */ + if (hsz > ssz || hsz < sizeof(*h)) + return NULL; + /* Header has to be verified when header_crc32 is zero */ orgcrc = le32_to_cpu(h->header_crc32); h->header_crc32 = 0; - crc = count_crc32((unsigned char *) h, le32_to_cpu(h->header_size)); + crc = count_crc32((unsigned char *) h, hsz); if (crc != orgcrc) { DBG(DEBUG_LOWPROBE, printf("GPT header corrupted\n")); return NULL; @@ -235,7 +255,8 @@ static struct gpt_header *get_gpt_header( return NULL; } - /* The header seems valid, save it */ + /* The header seems valid, save it + * (we don't care about zeros in hdr->reserved2 area) */ memcpy(hdr, h, sizeof(*h)); h = hdr; @@ -349,9 +370,6 @@ const struct blkid_idinfo gpt_pt_idinfo = * skip the legacy MBR. We follows this behavior and MBR is optional. * See is_valid_pmbr(). * - * It would be possible to check for "EFI PART" at begin of the disk, - * but the primary GPT is not required (in force mode). - * * It means we have to always call probe_gpt_pt(). */ .magics = BLKID_NONE_MAGIC diff --git a/shlibs/blkid/src/probe.c b/shlibs/blkid/src/probe.c index 078669f4..27bcf3d8 100644 --- a/shlibs/blkid/src/probe.c +++ b/shlibs/blkid/src/probe.c @@ -931,7 +931,7 @@ blkid_loff_t blkid_probe_get_size(blkid_probe pr) * blkid_probe_get_sectorsize: * @pr: probe * - * Returns: block device hardware sector size (BLKSSZGET ioctl, default 512). + * Returns: block device logical sector size (BLKSSZGET ioctl, default 512). */ unsigned int blkid_probe_get_sectorsize(blkid_probe pr) {