aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Soltys <soltys@ziu.info>2014-11-26 01:34:58 +0100
committerGene Cumm <gene.cumm@gmail.com>2015-03-15 04:39:24 -0400
commit7fb6d3a2c546ff77af8f33fd9dc95cbbc6e5771f (patch)
tree2e222c02ad3df6d100fe801c7f63b1ba30d5bba0
parent1d09bc044a3aea7edf15caf28dd71308137c57e4 (diff)
downloadsyslinux-7fb6d3a2c546ff77af8f33fd9dc95cbbc6e5771f.tar.gz
syslinux-7fb6d3a2c546ff77af8f33fd9dc95cbbc6e5771f.tar.xz
syslinux-7fb6d3a2c546ff77af8f33fd9dc95cbbc6e5771f.zip
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@ziu.info>
-rw-r--r--com32/chain/options.c13
-rw-r--r--com32/chain/partiter.c52
-rw-r--r--com32/chain/partiter.h2
-rw-r--r--doc/chain.txt13
4 files changed, 57 insertions, 23 deletions
diff --git a/com32/chain/options.c b/com32/chain/options.c
index a99e0d7b..3eecebde 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 287205f7..3e678aa3 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 22c0e42f..6d4fdb63 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 effd508e..d22a0890 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