diff --git a/include/crc32.h b/include/crc32.h index 26169109e..ff2dd99d8 100644 --- a/include/crc32.h +++ b/include/crc32.h @@ -5,6 +5,8 @@ #include extern uint32_t crc32(uint32_t seed, const unsigned char *buf, size_t len); +extern uint32_t crc32_exclude_offset(uint32_t seed, const unsigned char *buf, size_t len, + size_t exclude_off, size_t exclude_len); #endif diff --git a/lib/crc32.c b/lib/crc32.c index be98f1a8d..0c986288d 100644 --- a/lib/crc32.c +++ b/lib/crc32.c @@ -98,6 +98,11 @@ static const uint32_t crc32_tab[] = { 0x2d02ef8dL }; +static inline uint32_t crc32_add_char(uint32_t crc, unsigned char c) +{ + return crc32_tab[(crc ^ c) & 0xff] ^ (crc >> 8); +} + /* * This a generic crc32() function, it takes seed as an argument, * and does __not__ xor at the end. Then individual users can do @@ -109,10 +114,29 @@ uint32_t crc32(uint32_t seed, const unsigned char *buf, size_t len) const unsigned char *p = buf; while (len) { - crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8); + crc = crc32_add_char(crc, *p++); len--; } return crc; } +uint32_t crc32_exclude_offset(uint32_t seed, const unsigned char *buf, size_t len, + size_t exclude_off, size_t exclude_len) +{ + uint32_t crc = seed; + const unsigned char *p = buf; + size_t i; + + for (i = 0; i < len; i++) { + unsigned char x = *p++; + + if (i >= exclude_off && i < exclude_off + exclude_len) + x = 0; + + crc = crc32_add_char(crc, x); + } + + return crc; +} + diff --git a/libblkid/src/partitions/gpt.c b/libblkid/src/partitions/gpt.c index 665577fa4..26f047442 100644 --- a/libblkid/src/partitions/gpt.c +++ b/libblkid/src/partitions/gpt.c @@ -102,9 +102,10 @@ struct gpt_entry { /* * EFI uses crc32 with ~0 seed and xor's with ~0 at the end. */ -static inline uint32_t count_crc32(const unsigned char *buf, size_t len) +static inline uint32_t count_crc32(const unsigned char *buf, size_t len, + size_t exclude_off, size_t exclude_len) { - return (crc32(~0L, buf, len) ^ ~0L); + return (crc32_exclude_offset(~0L, buf, len, exclude_off, exclude_len) ^ ~0L); } static inline unsigned char *get_lba_buffer(blkid_probe pr, @@ -207,7 +208,7 @@ static struct gpt_header *get_gpt_header( uint64_t lastlba) { struct gpt_header *h; - uint32_t crc, orgcrc; + uint32_t crc; uint64_t lu, fu; size_t esz; uint32_t hsz, ssz; @@ -231,12 +232,11 @@ static struct gpt_header *get_gpt_header( return NULL; /* Header has to be verified when header_crc32 is zero */ - orgcrc = h->header_crc32; - h->header_crc32 = 0; - crc = count_crc32((unsigned char *) h, hsz); - h->header_crc32 = orgcrc; + crc = count_crc32((unsigned char *) h, hsz, + offsetof(struct gpt_header, header_crc32), + sizeof(h->header_crc32)); - if (crc != le32_to_cpu(orgcrc)) { + if (crc != le32_to_cpu(h->header_crc32)) { DBG(LOWPROBE, ul_debug("GPT header corrupted")); return NULL; } @@ -289,7 +289,7 @@ static struct gpt_header *get_gpt_header( } /* Validate entries */ - crc = count_crc32((unsigned char *) *ents, esz); + crc = count_crc32((unsigned char *) *ents, esz, 0, 0); if (crc != le32_to_cpu(h->partition_entry_array_crc32)) { DBG(LOWPROBE, ul_debug("GPT entries corrupted")); return NULL; diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c index 81741679a..607cb32cc 100644 --- a/libfdisk/src/gpt.c +++ b/libfdisk/src/gpt.c @@ -845,11 +845,31 @@ fail: return NULL; } -static inline uint32_t count_crc32(const unsigned char *buf, size_t len) +static inline uint32_t count_crc32(const unsigned char *buf, size_t len, + size_t ex_off, size_t ex_len) { - return (crc32(~0L, buf, len) ^ ~0L); + return (crc32_exclude_offset(~0L, buf, len, ex_off, ex_len) ^ ~0L); } +static inline uint32_t gpt_header_count_crc32(struct gpt_header *header) +{ + return count_crc32((unsigned char *) header, /* buffer */ + le32_to_cpu(header->size), /* size of buffer */ + offsetof(struct gpt_header, crc32), /* exclude */ + sizeof(header->crc32)); /* size of excluded area */ +} + +static inline uint32_t gpt_entryarr_count_crc32(struct gpt_header *header, struct gpt_entry *ents) +{ + size_t arysz = 0; + + arysz = le32_to_cpu(header->npartition_entries) * + le32_to_cpu(header->sizeof_partition_entry); + + return count_crc32((unsigned char *) ents, arysz, 0, 0); +} + + /* * Recompute header and partition array 32bit CRC checksums. * This function does not fail - if there's corruption, then it @@ -857,24 +877,13 @@ static inline uint32_t count_crc32(const unsigned char *buf, size_t len) */ static void gpt_recompute_crc(struct gpt_header *header, struct gpt_entry *ents) { - uint32_t crc = 0; - size_t entry_sz = 0; - if (!header) return; - /* header CRC */ - header->crc32 = 0; - crc = count_crc32((unsigned char *) header, le32_to_cpu(header->size)); - header->crc32 = cpu_to_le32(crc); + header->partition_entry_array_crc32 = + cpu_to_le32( gpt_entryarr_count_crc32(header, ents) ); - /* partition entry array CRC */ - header->partition_entry_array_crc32 = 0; - entry_sz = le32_to_cpu(header->npartition_entries) * - le32_to_cpu(header->sizeof_partition_entry); - - crc = count_crc32((unsigned char *) ents, entry_sz); - header->partition_entry_array_crc32 = cpu_to_le32(crc); + header->crc32 = cpu_to_le32( gpt_header_count_crc32(header) ); } /* @@ -883,28 +892,20 @@ static void gpt_recompute_crc(struct gpt_header *header, struct gpt_entry *ents) */ static int gpt_check_header_crc(struct gpt_header *header, struct gpt_entry *ents) { - uint32_t crc, orgcrc = le32_to_cpu(header->crc32); + uint32_t orgcrc = le32_to_cpu(header->crc32), + crc = gpt_header_count_crc32(header); - header->crc32 = 0; - crc = count_crc32((unsigned char *) header, le32_to_cpu(header->size)); - header->crc32 = cpu_to_le32(orgcrc); - - if (crc == le32_to_cpu(header->crc32)) + if (crc == orgcrc) return 1; /* - * If we have checksum mismatch it may be due to stale data, - * like a partition being added or deleted. Recompute the CRC again - * and make sure this is not the case. + * If we have checksum mismatch it may be due to stale data, like a + * partition being added or deleted. Recompute the CRC again and make + * sure this is not the case. */ if (ents) { gpt_recompute_crc(header, ents); - orgcrc = le32_to_cpu(header->crc32); - header->crc32 = 0; - crc = count_crc32((unsigned char *) header, le32_to_cpu(header->size)); - header->crc32 = cpu_to_le32(orgcrc); - - return crc == le32_to_cpu(header->crc32); + return gpt_header_count_crc32(header) == orgcrc; } return 0; @@ -917,23 +918,11 @@ static int gpt_check_header_crc(struct gpt_header *header, struct gpt_entry *ent static int gpt_check_entryarr_crc(struct gpt_header *header, struct gpt_entry *ents) { - int ret = 0; - ssize_t entry_sz; - uint32_t crc; - if (!header || !ents) - goto done; + return 0; - entry_sz = le32_to_cpu(header->npartition_entries) * - le32_to_cpu(header->sizeof_partition_entry); - - if (!entry_sz) - goto done; - - crc = count_crc32((unsigned char *) ents, entry_sz); - ret = (crc == le32_to_cpu(header->partition_entry_array_crc32)); -done: - return ret; + return gpt_entryarr_count_crc32(header, ents) == + le32_to_cpu(header->partition_entry_array_crc32); } static int gpt_check_lba_sanity(struct fdisk_context *cxt, struct gpt_header *header)