summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2015-09-11 17:51:31 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2015-09-11 17:51:31 +0000
commite4735d359fb10e93374639ec3b4c97aacd5dc18e (patch)
tree9fecdc83007b6dfca933dd012c438d5112813a80
parenta0c321c80744d259e5189037309325cff87f791f (diff)
Hoist all the GPT header checks into gpt_chk_header(). Tweak remaining
logic a bit so that an invalid primary header/partition entries table does not cause readgptlabel() to exit before the secondary header is tried.
-rw-r--r--sys/kern/subr_disk.c124
1 files changed, 64 insertions, 60 deletions
diff --git a/sys/kern/subr_disk.c b/sys/kern/subr_disk.c
index b5b6857c094..5c029a252b6 100644
--- a/sys/kern/subr_disk.c
+++ b/sys/kern/subr_disk.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: subr_disk.c,v 1.213 2015/09/11 15:04:01 krw Exp $ */
+/* $OpenBSD: subr_disk.c,v 1.214 2015/09/11 17:51:30 krw Exp $ */
/* $NetBSD: subr_disk.c,v 1.17 1996/03/16 23:17:08 christos Exp $ */
/*
@@ -106,7 +106,7 @@ int readdisksector(struct buf *, void (*)(struct buf *), struct disklabel *,
u_int64_t);
int gpt_chk_mbr(struct dos_partition *, struct disklabel *);
-int gpt_chk_hdr(struct gpt_header *);
+int gpt_chk_hdr(struct gpt_header *, struct disklabel *);
int gpt_chk_parts(struct gpt_header *, struct gpt_partition *);
int gpt_get_fstype(struct uuid *);
@@ -607,15 +607,68 @@ gpt_chk_mbr(struct dos_partition *dp, struct disklabel *lp)
}
int
-gpt_chk_hdr(struct gpt_header *gh)
+gpt_chk_hdr(struct gpt_header *gh, struct disklabel *lp)
{
- u_int32_t orig_gh_csum = gh->gh_csum;
+ uint64_t ghpartlba;
+ uint64_t ghlbaend, ghlbastart;
+ uint32_t orig_gh_csum = gh->gh_csum;
+ uint32_t ghsize, ghpartsize, ghpartspersec, ghpartnum;
+
gh->gh_csum = 0;
gh->gh_csum = crc32(0, (unsigned char *)gh, gh->gh_size);
if (orig_gh_csum != gh->gh_csum)
return (EINVAL);
+ if (letoh64(gh->gh_sig) != GPTSIGNATURE)
+ return (EINVAL);
+
+ /* we only support version 1.0 */
+ if (letoh32(gh->gh_rev) != GPTREVISION)
+ return (EINVAL);
+
+ ghsize = letoh32(gh->gh_size);
+ ghpartsize = letoh32(gh->gh_part_size);
+ ghpartspersec = lp->d_secsize / ghpartsize;
+ ghpartnum = letoh32(gh->gh_part_num);
+ ghpartlba = letoh64(gh->gh_part_lba);
+ ghlbaend = letoh64(gh->gh_lba_end);
+ ghlbastart = letoh64(gh->gh_lba_start);
+
+ /*
+ * Header size must be greater than or equal to 92 and less
+ * than or equal to the logical block size.
+ */
+ if (ghsize < GPTMINHDRSIZE || ghsize > lp->d_secsize)
+ return (EINVAL);
+
+ if (ghlbastart >= DL_GETDSIZE(lp) ||
+ ghlbaend >= DL_GETDSIZE(lp) ||
+ ghpartlba >= DL_GETDSIZE(lp))
+ return (EINVAL);
+
+ /*
+ * Size per partition entry shall be 128*(2**n) with n >= 0.
+ * We don't support partition entries larger than block size.
+ */
+ if (ghpartsize % GPTMINPARTSIZE || ghpartsize > lp->d_secsize
+ || ghpartspersec == 0) {
+ DPRINTF("invalid partition size\n");
+ return (EINVAL);
+ }
+
+ /* XXX: we don't support multiples of GPTMINPARTSIZE yet */
+ if (ghpartsize != GPTMINPARTSIZE) {
+ DPRINTF("partition sizes larger than %d bytes are not "
+ "supported", GPTMINPARTSIZE);
+ return (EINVAL);
+ }
+
+ if (letoh64(gh->gh_lba_alt) >= DL_GETDSIZE(lp)) {
+ DPRINTF("alternate header's position is bogus\n");
+ return (EINVAL);
+ }
+
return 0;
}
@@ -701,7 +754,6 @@ readgptlabel(struct buf *bp, void (*strat)(struct buf *),
for (sector = GPTSECTOR; ; sector = DL_GETDSIZE(lp)-1, altheader = 1) {
uint64_t ghpartlba;
- uint32_t ghsize;
uint32_t ghpartsize;
uint32_t ghpartspersec;
@@ -714,65 +766,21 @@ readgptlabel(struct buf *bp, void (*strat)(struct buf *),
}
bcopy(bp->b_data, &gh, sizeof(gh));
- ghsize = letoh32(gh.gh_size);
- ghpartsize = letoh32(gh.gh_part_size);
- ghpartspersec = lp->d_secsize / ghpartsize;
- ghpartnum = letoh32(gh.gh_part_num);
- ghpartlba = letoh64(gh.gh_part_lba);
- ghlbaend = letoh64(gh.gh_lba_end);
- ghlbastart = letoh64(gh.gh_lba_start);
-
- if (letoh64(gh.gh_sig) != GPTSIGNATURE)
- return (EINVAL);
-
- /* we only support version 1.0 */
- if (letoh32(gh.gh_rev) != GPTREVISION)
- return (EINVAL);
- if (gpt_chk_hdr(&gh)) {
- /* header broken, using alternate header */
+ if (gpt_chk_hdr(&gh, lp)) {
if (altheader) {
DPRINTF("alternate header also broken\n");
return (EINVAL);
}
-
- if (letoh64(gh.gh_lba_alt) >= DL_GETDSIZE(lp)) {
- DPRINTF("alternate header's position is "
- "bogus\n");
- return (EINVAL);
- }
-
continue;
}
- /*
- * Header size must be greater than or equal to 92 and less
- * than or equal to the logical block size.
- */
- if (ghsize < GPTMINHDRSIZE || ghsize > lp->d_secsize)
- return (EINVAL);
-
- if (ghlbastart >= DL_GETDSIZE(lp) ||
- ghlbaend >= DL_GETDSIZE(lp) ||
- ghpartlba >= DL_GETDSIZE(lp))
- return (EINVAL);
-
- /*
- * Size per partition entry shall be 128*(2**n) with n >= 0.
- * We don't support partition entries larger than block size.
- */
- if (ghpartsize % GPTMINPARTSIZE || ghpartsize > lp->d_secsize
- || ghpartspersec == 0) {
- DPRINTF("invalid partition size\n");
- return (EINVAL);
- }
-
- /* XXX: we don't support multiples of GPTMINPARTSIZE yet */
- if (ghpartsize != GPTMINPARTSIZE) {
- DPRINTF("partition sizes larger than %d bytes are not "
- "supported", GPTMINPARTSIZE);
- return (EINVAL);
- }
+ ghpartsize = letoh32(gh.gh_part_size);
+ ghpartspersec = lp->d_secsize / ghpartsize;
+ ghpartnum = letoh32(gh.gh_part_num);
+ ghpartlba = letoh64(gh.gh_part_lba);
+ ghlbaend = letoh64(gh.gh_lba_end);
+ ghlbastart = letoh64(gh.gh_lba_start);
/* read GPT partition entry array */
gp = mallocarray(ghpartnum, sizeof(struct gpt_partition),
@@ -800,16 +808,12 @@ readgptlabel(struct buf *bp, void (*strat)(struct buf *),
}
if (gpt_chk_parts(&gh, gp)) {
- DPRINTF("partition entries broken, using alternate "
- "header\n");
free(gp, M_DEVBUF, gpsz);
-
if (altheader) {
DPRINTF("alternate partition entries are also "
"broken\n");
return (EINVAL);
}
-
continue;
}
break;