From 7fb6d3a2c546ff77af8f33fd9dc95cbbc6e5771f Mon Sep 17 00:00:00 2001 From: Michal Soltys Date: Wed, 26 Nov 2014 01:34:58 +0100 Subject: 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 --- 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 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 -- cgit v1.2.1