summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/crc32.h2
-rw-r--r--lib/crc32.c26
-rw-r--r--libblkid/src/partitions/gpt.c18
-rw-r--r--libfdisk/src/gpt.c81
4 files changed, 71 insertions, 56 deletions
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 <stdint.h>
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);
-
- /* 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);
+ header->partition_entry_array_crc32 =
+ cpu_to_le32( gpt_entryarr_count_crc32(header, ents) );
- 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);
-
- header->crc32 = 0;
- crc = count_crc32((unsigned char *) header, le32_to_cpu(header->size));
- header->crc32 = cpu_to_le32(orgcrc);
+ uint32_t orgcrc = le32_to_cpu(header->crc32),
+ crc = gpt_header_count_crc32(header);
- 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;
-
- entry_sz = le32_to_cpu(header->npartition_entries) *
- le32_to_cpu(header->sizeof_partition_entry);
-
- if (!entry_sz)
- goto done;
+ return 0;
- 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)