summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_disk.c
diff options
context:
space:
mode:
authorkrw <krw@openbsd.org>2015-09-10 14:28:17 +0000
committerkrw <krw@openbsd.org>2015-09-10 14:28:17 +0000
commit069b6aac1fa48713c421165e8a4b6d86686a91a7 (patch)
tree8aeebfbb8e78c44e0425aca0a36c2805cf0c5cca /sys/kern/subr_disk.c
parentmlink tls_handshake; (diff)
downloadwireguard-openbsd-069b6aac1fa48713c421165e8a4b6d86686a91a7.tar.xz
wireguard-openbsd-069b6aac1fa48713c421165e8a4b6d86686a91a7.zip
Call readgptlabel() from readdoslabel() instead of MD readdisklabel().
Call it if and only if there is an MBR on sector 0 that contains 1 and only 1 partition; that partition is an EFI partition; and it covers the entire disk or as much of the disk as can be covered in an MBR partition. Be paranoid about restoring any possible tweaks to the label being built in the case that readgptlabel() fails, and in that case return to the readdoslabel() code. ok deraadt@
Diffstat (limited to 'sys/kern/subr_disk.c')
-rw-r--r--sys/kern/subr_disk.c60
1 files changed, 59 insertions, 1 deletions
diff --git a/sys/kern/subr_disk.c b/sys/kern/subr_disk.c
index bca3caf3faf..8c2ed620f85 100644
--- a/sys/kern/subr_disk.c
+++ b/sys/kern/subr_disk.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: subr_disk.c,v 1.202 2015/09/10 14:11:53 krw Exp $ */
+/* $OpenBSD: subr_disk.c,v 1.203 2015/09/10 14:28:17 krw Exp $ */
/* $NetBSD: subr_disk.c,v 1.17 1996/03/16 23:17:08 christos Exp $ */
/*
@@ -56,6 +56,7 @@
#include <sys/dkio.h>
#include <sys/vnode.h>
#include <sys/task.h>
+#include <sys/stdint.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
@@ -105,6 +106,9 @@ void disk_attach_callback(void *);
int readdisksector(struct buf *, void (*)(struct buf *), struct disklabel *,
u_int64_t);
+#ifdef GPT
+int gpt_chk_mbr(struct dos_partition *, struct disklabel *);
+#endif
/*
* Compute checksum for disk label.
@@ -366,6 +370,23 @@ readdoslabel(struct buf *bp, void (*strat)(struct buf *),
(bp->b_data[511] & 0xff);
if (mbrtest != 0x55aa)
goto notmbr;
+#ifdef GPT
+ if (gpt_chk_mbr(dp, lp) == 0) {
+ error = readgptlabel(bp, strat, lp,
+ partoffp ? &dospartoff : NULL, spoofonly);
+ if (error == 0) {
+ if (partoffp)
+ *partoffp = dospartoff;
+ return (0);
+ } else {
+ /* Restore all potentially tweakee's */
+ dospartoff = 0;
+ DL_SETBSTART(lp, 0);
+ DL_SETBEND(lp, DL_GETDSIZE(lp));
+ goto notmbr;
+ }
+ }
+#endif
}
if (ourpart == -1) {
@@ -556,6 +577,43 @@ int gpt_chk_hdr(struct gpt_header *);
int gpt_chk_parts(struct gpt_header *, struct gpt_partition *);
int get_fstype(struct uuid *);
+/*
+ * Returns 0 if the MBR with the provided partition array is a GPT protective
+ * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only
+ * one MBR partition, an EFI partition that either covers the whole disk or as
+ * much of it as is possible with a 32bit size field.
+ *
+ * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!**
+ */
+int
+gpt_chk_mbr(struct dos_partition *dp, struct disklabel *lp)
+{
+ struct dos_partition *dp2;
+ u_int64_t dsize;
+ int efi, found, i;
+ u_int32_t psize;
+
+ found = efi = 0;
+ for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) {
+ if (dp2->dp_typ == DOSPTYP_UNUSED)
+ continue;
+ found++;
+ if (dp2->dp_typ != DOSPTYP_EFI)
+ continue;
+ dsize = DL_GETDSIZE(lp);
+ psize = letoh32(dp2->dp_size);
+ if (psize == (dsize - 1) ||
+ psize == UINT32_MAX) {
+ if (letoh32(dp2->dp_start) == 1)
+ efi++;
+ }
+ }
+ if (found == 1 && efi == 1)
+ return (0);
+
+ return (EINVAL);
+}
+
int
gpt_chk_hdr(struct gpt_header *gh)
{