[syslinux:master] chain/partiter: add options to ignore GPT crc checks

syslinux-bot for Michal Soltys soltys at ziu.info
Sun Mar 15 01:45:10 PDT 2015


Commit-ID:  7fb6d3a2c546ff77af8f33fd9dc95cbbc6e5771f
Gitweb:     http://www.syslinux.org/commit/7fb6d3a2c546ff77af8f33fd9dc95cbbc6e5771f
Author:     Michal Soltys <soltys at ziu.info>
AuthorDate: Wed, 26 Nov 2014 01:34:58 +0100
Committer:  Gene Cumm <gene.cumm at gmail.com>
CommitDate: Sun, 15 Mar 2015 04:39:24 -0400

chain/partiter: add options to ignore GPT crc checks

This can be useful to force boot even if checksums of GPT header and/or
partition list are invalid. This works independently from 'strict'
option.

Signed-off-by: Michal Soltys <soltys at ziu.info>

---
 com32/chain/options.c  | 13 ++++++++++++-
 com32/chain/partiter.c | 52 +++++++++++++++++++++++++++++++-------------------
 com32/chain/partiter.h |  2 +-
 doc/chain.txt          | 13 ++++++++++++-
 4 files changed, 57 insertions(+), 23 deletions(-)

diff --git a/com32/chain/options.c b/com32/chain/options.c
index a99e0d7..3eecebd 100644
--- a/com32/chain/options.c
+++ b/com32/chain/options.c
@@ -132,6 +132,8 @@ static void usage(void)
 "  keeppxe              Keep the PXE and UNDI stacks in memory (PXELINUX)",
 "  warn                 Wait for a keypress to continue chainloading",
 "  break                Don't chainload",
+"  gpthcrc              Perform gpt header crc check",
+"  gptlcrc              Perform gpt list crc check",
 "  strict[=<0|1|2>]     Set the level of strictness in sanity checks",
 "                       - strict w/o any value is the same as strict=2",
 "  relax                The same as strict=0",
@@ -174,7 +176,8 @@ void opt_set_defs(void)
     opt.maps = true;	    /* by def. map sector */
     opt.hand = true;	    /* by def. prepare handover */
     opt.brkchain = false;   /* by def. do chainload */
-    opt.piflags = PIF_STRICT;	/* by def. be strict, but ignore disk sizes */
+    /* strict but ignore disk size, do all gpt crc checks */
+    opt.piflags = PIF_STRICT | PIF_GPTHCRC | PIF_GPTLCRC;
     opt.foff = opt.soff = opt.fip = opt.sip = 0x7C00;
     opt.drivename = "boot";
 #ifdef DEBUG
@@ -359,6 +362,14 @@ int opt_parse_args(int argc, char *argv[])
 		case '1': opt.piflags |= PIF_STRICT; break;
 		default:;
 	    }
+	} else if (!strcmp(argv[i], "gpthcrc")) {
+	    opt.piflags |= PIF_GPTHCRC;
+	} else if (!strcmp(argv[i], "nogpthcrc")) {
+	    opt.piflags &= ~PIF_GPTHCRC;
+	} else if (!strcmp(argv[i], "gptlcrc")) {
+	    opt.piflags |= PIF_GPTLCRC;
+	} else if (!strcmp(argv[i], "nogptlcrc")) {
+	    opt.piflags &= ~PIF_GPTLCRC;
 	} else if (!strcmp(argv[i], "warn")) {
 	    opt.warn = true;
 	} else if (!strcmp(argv[i], "nowarn")) {
diff --git a/com32/chain/partiter.c b/com32/chain/partiter.c
index 287205f..3e678aa 100644
--- a/com32/chain/partiter.c
+++ b/com32/chain/partiter.c
@@ -412,16 +412,29 @@ static inline int valid_crc(uint32_t crc, const uint8_t *buf, unsigned int siz)
     return crc == crc32(crc32(0, NULL, 0), buf, siz);
 }
 
-static int valid_crc_hdr(void *buf)
+static int valid_crc_gpth(struct disk_gpt_header *gh, int flags)
 {
-    struct disk_gpt_header *gh = buf;
-    uint32_t crc = gh->chksum;
-    int valid;
+    uint32_t crc, crcc;
 
+    if (!(flags & PIF_GPTHCRC))
+	return 1;
+
+    crc = gh->chksum;
     gh->chksum = 0;
-    valid = crc == crc32(crc32(0, NULL, 0), buf, gh->hdr_size);
+    crcc = crc32(crc32(0, NULL, 0), (const uint8_t *)gh, gh->hdr_size);
     gh->chksum = crc;
-    return valid;
+    return crc == crcc;
+}
+
+static int valid_crc_gptl(const struct disk_gpt_header *gh, const struct disk_gpt_part_entry *gl, int flags)
+{
+    uint32_t crcc;
+
+    if (!(flags & PIF_GPTLCRC))
+	return 1;
+
+    crcc = crc32(crc32(0, NULL, 0), (const uint8_t *)gl, gh->part_size * gh->part_count);
+    return gh->table_chksum == crcc;
 }
 
 static int pi_next_(struct part_iter *iter)
@@ -582,7 +595,7 @@ static struct disk_gpt_header *try_gpt_hdr(const struct disk_info *di, int sec,
 	sprintf(errbuf, "Unable to read %s GPT header.", desc);
 	goto out;
     }
-    if(!valid_crc_hdr(gpth)) {
+    if(!valid_crc_gpth(gpth, flags)) {
 	sprintf(errbuf, "Invalid checksum of %s GPT header.", desc);
 	goto out;
     }
@@ -597,18 +610,16 @@ out:
     return NULL;
 }
 
-static struct disk_gpt_part_entry *try_gpt_list(const struct disk_info *di, const struct disk_gpt_header *gpth, int alt)
+static struct disk_gpt_part_entry *try_gpt_list(const struct disk_info *di, const struct disk_gpt_header *gpth, int alt, int flags)
 {
     int pri = gpth->lba_cur < gpth->lba_alt;
     const char *desc = alt ? "alternative" : "main";
     struct disk_gpt_part_entry *gptl;
     char errbuf[64];
-    uint64_t gpt_lsiz;	    /* size of GPT partition list in bytes */
-    uint64_t gpt_lcnt;	    /* size of GPT partition in sectors */
+    uint32_t gpt_lcnt;	    /* size of GPT partition in sectors */
     uint64_t gpt_loff;	    /* offset to GPT partition list in sectors */
 
-    gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count;
-    gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps;
+    gpt_lcnt = (gpth->part_size * gpth->part_count + di->bps - 1) / di->bps;
     if (!alt) {
 	/* prefer header value for partition table if not asking for alternative */
 	gpt_loff = gpth->lba_table;
@@ -623,16 +634,17 @@ static struct disk_gpt_part_entry *try_gpt_list(const struct disk_info *di, cons
     gptl = disk_read_sectors(di, gpt_loff, gpt_lcnt);
     if (!gptl) {
 	sprintf(errbuf, "Unable to read %s GPT partition list.", desc);
-	try_gpt_we(errbuf, alt);
-	return NULL;
+	goto out;
     }
-    if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, gpt_lsiz)) {
+    if (!valid_crc_gptl(gpth, gptl, flags)) {
 	sprintf(errbuf, "Invalid checksum of %s GPT partition list.", desc);
-	try_gpt_we(errbuf, alt);
-	free(gptl);
-	return NULL;
+	goto out;
     }
     return gptl;
+out:
+    try_gpt_we(errbuf, alt);
+    free(gptl);
+    return NULL;
 }
 
 /* pi_begin() - validate and and get proper iterator for a disk described by di */
@@ -687,9 +699,9 @@ struct part_iter *pi_begin(const struct disk_info *di, int flags)
 	dprintf("Looks like a GPT v1.0 disk.\n");
 	disk_gpt_header_dump(gpth);
 #endif
-	gptl = try_gpt_list(di, gpth, 0);
+	gptl = try_gpt_list(di, gpth, 0, flags);
 	if (!gptl)
-	    gptl = try_gpt_list(di, gpth, 1);
+	    gptl = try_gpt_list(di, gpth, 1, flags);
 	if (!gptl)
 	    goto out;
 
diff --git a/com32/chain/partiter.h b/com32/chain/partiter.h
index 22c0e42..6d4fdb6 100644
--- a/com32/chain/partiter.h
+++ b/com32/chain/partiter.h
@@ -46,7 +46,7 @@ enum {PI_ERRLOAD = -31, PI_INSANE, PI_OK = 0, PI_DONE};
 
 /* flags */
 
-enum {PIF_STEPALL = 1, PIF_PREFMBR = 2, PIF_STRICT = 4, PIF_STRICTER = 8};
+enum {PIF_STEPALL = 1, PIF_PREFMBR = 2, PIF_STRICT = 4, PIF_STRICTER = 8, PIF_GPTHCRC = 16, PIF_GPTLCRC = 32};
 
 struct itertype;
 struct part_iter;
diff --git a/doc/chain.txt b/doc/chain.txt
index effd508..d22a089 100644
--- a/doc/chain.txt
+++ b/doc/chain.txt
@@ -235,6 +235,18 @@ Useful to see warnings emited by the chain module.
 In the case of presence of non-standard hybrid MBR/GPT layout, this flag makes
 chain module prefer MBR layout over GPT.
 
+	*gpthcrc
+	nogpthcrc
+
+GPT header contains its crc32 checksum. By default the partition iterator
+verifies it and aborts in case of mismatch.
+
+	*gptlcrc
+	nogptlcrc
+
+GPT header contains crc32 checksum of GPT partition list. By default the
+partition iterator verifies it and aborts in case of mismatch.
+
 	strict[=<0|1|2>]
 	*strict=1
 	relax
@@ -252,7 +264,6 @@ disk corruption in some later EMBR partition.
 - relax and nostrict are equivalent to strict=0
 - norelax and strict are equivalent to strict=2
 
-
 	break
 	*nobreak
 	break sets: nofile nomaps nohand


More information about the Syslinux-commits mailing list