diff options
Diffstat (limited to 'com32')
-rw-r--r-- | com32/chain/options.c | 13 | ||||
-rw-r--r-- | com32/chain/partiter.c | 52 | ||||
-rw-r--r-- | com32/chain/partiter.h | 2 |
3 files changed, 45 insertions, 22 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; |