lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Mon, 22 Jun 2015 22:52:53 +0100
From:	Ross Lagerwall <rosslagerwall@...il.com>
To:	linux-kernel@...r.kernel.org
Cc:	Jens Axboe <axboe@...nel.dk>, Fabian Frederick <fabf@...net.be>,
	Ross Lagerwall <rosslagerwall@...il.com>
Subject: [PATCH RESEND] partitions/msdos: Support relative offset BSD partitions

FreeBSD can use relative addressing for the offsets in its disklabel (it
appears that bsdlabel uses relative offsets and sysinstall uses absolute
offsets). When Linux reads the disklabel, either the partitions fail the
sanity checks and are considered invalid or they use the wrong offset
and data corruption ensues.

To fix this, determine if relative addressing is used by looking at
partition "c" in the disk label which is meant to represent the entire
slice. If "c" has an offset of 0, then relative addressing is used,
otherwise absolute addressing is used.

This change includes a cleanup to allow altering behavior based on the
type of disklabel.

The idea comes from the FreeBSD patch for GRUB:
http://lists.freebsd.org/pipermail/freebsd-ports-bugs/2010-November/201081.html

Signed-off-by: Ross Lagerwall <rosslagerwall@...il.com>
---
 block/partitions/msdos.c | 33 ++++++++++++++++++++++++++-------
 include/linux/genhd.h    |  1 +
 2 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/block/partitions/msdos.c b/block/partitions/msdos.c
index 93e7c1b..e8421c4 100644
--- a/block/partitions/msdos.c
+++ b/block/partitions/msdos.c
@@ -265,18 +265,30 @@ static void parse_solaris_x86(struct parsed_partitions *state,
 }
 
 #if defined(CONFIG_BSD_DISKLABEL)
+enum flavour {
+	FLAVOUR_BSD,
+	FLAVOUR_NETBSD,
+	FLAVOUR_OPENBSD,
+};
+
+static const char *const flavours[] = {
+	[FLAVOUR_BSD]		= "bsd",
+	[FLAVOUR_NETBSD]	= "netbsd",
+	[FLAVOUR_OPENBSD]	= "openbsd",
+};
 /*
  * Create devices for BSD partitions listed in a disklabel, under a
  * dos-like partition. See parse_extended() for more information.
  */
 static void parse_bsd(struct parsed_partitions *state,
-		      sector_t offset, sector_t size, int origin, char *flavour,
-		      int max_partitions)
+		      sector_t offset, sector_t size, int origin,
+		      enum flavour flavour, int max_partitions)
 {
 	Sector sect;
 	struct bsd_disklabel *l;
 	struct bsd_partition *p;
 	char tmp[64];
+	sector_t delta = 0;
 
 	l = read_part_sector(state, offset + 1, &sect);
 	if (!l)
@@ -286,11 +298,17 @@ static void parse_bsd(struct parsed_partitions *state,
 		return;
 	}
 
-	snprintf(tmp, sizeof(tmp), " %s%d: <%s:", state->name, origin, flavour);
+	snprintf(tmp, sizeof(tmp), " %s%d: <%s:", state->name, origin,
+		 flavours[flavour]);
 	strlcat(state->pp_buf, tmp, PAGE_SIZE);
 
 	if (le16_to_cpu(l->d_npartitions) < max_partitions)
 		max_partitions = le16_to_cpu(l->d_npartitions);
+	/* Determine if sector offsets are relative. */
+	if (BSD_WHOLE_DISK < le16_to_cpu(l->d_npartitions) &&
+	    flavour == FLAVOUR_BSD)
+		delta = offset -
+			le32_to_cpu(l->d_partitions[BSD_WHOLE_DISK].p_offset);
 	for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) {
 		sector_t bsd_start, bsd_size;
 
@@ -298,7 +316,7 @@ static void parse_bsd(struct parsed_partitions *state,
 			break;
 		if (p->p_fstype == BSD_FS_UNUSED)
 			continue;
-		bsd_start = le32_to_cpu(p->p_offset);
+		bsd_start = le32_to_cpu(p->p_offset) + delta;
 		bsd_size = le32_to_cpu(p->p_size);
 		if (offset == bsd_start && size == bsd_size)
 			/* full parent partition, we have it already */
@@ -323,7 +341,7 @@ static void parse_freebsd(struct parsed_partitions *state,
 			  sector_t offset, sector_t size, int origin)
 {
 #ifdef CONFIG_BSD_DISKLABEL
-	parse_bsd(state, offset, size, origin, "bsd", BSD_MAXPARTITIONS);
+	parse_bsd(state, offset, size, origin, FLAVOUR_BSD, BSD_MAXPARTITIONS);
 #endif
 }
 
@@ -331,7 +349,8 @@ static void parse_netbsd(struct parsed_partitions *state,
 			 sector_t offset, sector_t size, int origin)
 {
 #ifdef CONFIG_BSD_DISKLABEL
-	parse_bsd(state, offset, size, origin, "netbsd", BSD_MAXPARTITIONS);
+	parse_bsd(state, offset, size, origin, FLAVOUR_NETBSD,
+		  BSD_MAXPARTITIONS);
 #endif
 }
 
@@ -339,7 +358,7 @@ static void parse_openbsd(struct parsed_partitions *state,
 			  sector_t offset, sector_t size, int origin)
 {
 #ifdef CONFIG_BSD_DISKLABEL
-	parse_bsd(state, offset, size, origin, "openbsd",
+	parse_bsd(state, offset, size, origin, FLAVOUR_OPENBSD,
 		  OPENBSD_MAXPARTITIONS);
 #endif
 }
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index ec274e0..d60bfdd 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -491,6 +491,7 @@ struct solaris_x86_vtoc {
 #define BSD_MAXPARTITIONS	16
 #define OPENBSD_MAXPARTITIONS	16
 #define BSD_FS_UNUSED		0	/* disklabel unused partition entry ID */
+#define BSD_WHOLE_DISK		2	/* partition representing entire disk */
 struct bsd_disklabel {
 	__le32	d_magic;		/* the magic number */
 	__s16	d_type;			/* drive type */
-- 
2.4.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ