[syslinux] [PATCH 5/6] chain: implement strict=<0|1|2>

Michal Soltys soltys at ziu.info
Sun Jun 29 12:41:42 PDT 2014


This provides more fine grained control than single relax flag. to cover
case with wrong disk sizes.

relax and nostrict are equivalent to strict=0
norelax and strict are equivalent to strict=2

strict=1 does the same as strict=2, but ignores checks against disk size

The current default is strict=1. Options: 'fixchs', '[un]hide[all]' and
'save' will forcibly enable strict=2 (can be overridden by the user).

diff --git a/com32/chain/mangle.c b/com32/chain/mangle.c
index 6963574..3231e51 100644
--- a/com32/chain/mangle.c
+++ b/com32/chain/mangle.c
@@ -602,7 +602,7 @@ static int updchs(struct part_iter *iter, int ext)
      * lower than the start CHS.
      *
      * Both are harmless in case of a hole (and in non-hole case will make
-     * partiter complain about corrupt layout unless PIF_RELAX is set), but it
+     * partiter complain about corrupt layout if PIF_STRICT is set), but it
      * makes everything look silly and not really correct.
      *
      * Thus the approach as seen below.
diff --git a/com32/chain/options.c b/com32/chain/options.c
index 4e722a0..a99e0d7 100644
--- a/com32/chain/options.c
+++ b/com32/chain/options.c
@@ -132,7 +132,9 @@ 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",
-"  relax                Relax sanity checks",
+"  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",
 "  prefmbr              On hybrid MBR/GPT disks, prefer legacy layout",
 "",
 "  file=<file>          Load and execute <file>",
@@ -172,6 +174,7 @@ 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 */
     opt.foff = opt.soff = opt.fip = opt.sip = 0x7C00;
     opt.drivename = "boot";
 #ifdef DEBUG
@@ -303,12 +306,16 @@ int opt_parse_args(int argc, char *argv[])
 	    opt.hide = HIDE_OFF;
 	} else if (!strcmp(argv[i], "hide")) {
 	    opt.hide = HIDE_ON;
+	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
 	} else if (!strcmp(argv[i], "hideall")) {
 	    opt.hide = HIDE_ON | HIDE_EXT;
+	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
 	} else if (!strcmp(argv[i], "unhide")) {
 	    opt.hide = HIDE_ON | HIDE_REV;
+	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
 	} else if (!strcmp(argv[i], "unhideall")) {
 	    opt.hide = HIDE_ON | HIDE_EXT | HIDE_REV;
+	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
 	} else if (!strcmp(argv[i], "setbpb")) {
 	    opt.setbpb = true;
 	} else if (!strcmp(argv[i], "nosetbpb")) {
@@ -329,16 +336,29 @@ int opt_parse_args(int argc, char *argv[])
 	    opt.maps = false;
 	} else if (!strcmp(argv[i], "save")) {
 	    opt.save = true;
+	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
 	} else if (!strcmp(argv[i], "nosave")) {
 	    opt.save = false;
 	} else if (!strcmp(argv[i], "fixchs")) {
 	    opt.fixchs = true;
+	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
 	} else if (!strcmp(argv[i], "nofixchs")) {
 	    opt.fixchs = false;
-	} else if (!strcmp(argv[i], "relax")) {
-	    opt.piflags |= PIF_RELAX;
-	} else if (!strcmp(argv[i], "norelax")) {
-	    opt.piflags &= ~PIF_RELAX;
+	} else if (!strcmp(argv[i], "relax") || !strcmp(argv[i], "nostrict")) {
+	    opt.piflags &= ~(PIF_STRICT | PIF_STRICTER);
+	} else if (!strcmp(argv[i], "norelax") || !strcmp(argv[i], "strict")) {
+	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
+	} else if (!strncmp(argv[i], "strict=", 7)) {
+	    if (argv[i][7] < '0' || argv[i][7] > '2' || !argv[i][8]) {
+		error("Strict level must be 0, 1 or 2.");
+		goto bail;
+	    }
+	    opt.piflags &= ~(PIF_STRICT | PIF_STRICTER);
+	    switch (argv[i][7]) {
+		case '2': opt.piflags |= PIF_STRICTER;
+		case '1': opt.piflags |= PIF_STRICT; break;
+		default:;
+	    }
 	} 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 5c5b015..beeb1bd 100644
--- a/com32/chain/partiter.c
+++ b/com32/chain/partiter.c
@@ -176,7 +176,7 @@ static int notsane_logical(const struct part_iter *iter)
 	return -1;
     }
 
-    if (iter->flags & PIF_RELAX)
+    if (!(iter->flags & PIF_STRICT))
 	return 0;
 
     end_log = dp[0].start_lba + dp[0].length;
@@ -215,7 +215,7 @@ static int notsane_extended(const struct part_iter *iter)
 	return -1;
     }
 
-    if (iter->flags & PIF_RELAX)
+    if (!(iter->flags & PIF_STRICT))
 	return 0;
 
     end_ebr = dp[1].start_lba + dp[1].length;
@@ -245,13 +245,13 @@ static int notsane_primary(const struct part_iter *iter)
     if (!dp->ostype)
 	return 0;
 
-    if (iter->flags & PIF_RELAX)
+    if (!(iter->flags & PIF_STRICT))
 	return 0;
 
     if (!dp->start_lba ||
 	!dp->length ||
 	!sane(dp->start_lba, dp->length) ||
-	dp->start_lba + dp->length > iter->di.lbacnt) {
+	((iter->flags & PIF_STRICTER) && (dp->start_lba + dp->length > iter->di.lbacnt))) {
 	error("Primary partition (in MBR) with invalid offset and/or length.");
 	return -1;
     }
@@ -268,7 +268,7 @@ static int notsane_gpt(const struct part_iter *iter)
     if (guid_is0(&gp->type))
 	return 0;
 
-    if (iter->flags & PIF_RELAX)
+    if (!(iter->flags & PIF_STRICT))
 	return 0;
 
     if (gp->lba_first < iter->gpt.ufirst ||
@@ -602,7 +602,7 @@ static int notsane_gpt_hdr(const struct disk_info *di, const struct disk_gpt_hea
     uint64_t gpt_lsiz;	    /* size of GPT partition list in bytes */
     uint64_t gpt_lcnt;	    /* size of GPT partition in sectors */
 
-    if (flags & PIF_RELAX)
+    if (!(flags & PIF_STRICT))
 	return 0;
 
     gpt_loff = gpth->lba_table;
@@ -619,7 +619,7 @@ static int notsane_gpt_hdr(const struct disk_info *di, const struct disk_gpt_hea
 	    gpt_loff + gpt_lcnt > gpth->lba_first_usable ||
 	    !sane(gpth->lba_last_usable, gpt_lcnt) ||
 	    gpth->lba_last_usable + gpt_lcnt >= gpth->lba_alt ||
-	    gpth->lba_alt >= di->lbacnt ||
+	    ((flags & PIF_STRICTER) && (gpth->lba_alt >= di->lbacnt)) ||
 	    gpth->part_size < sizeof(struct disk_gpt_part_entry))
 	return -1;
 
diff --git a/com32/chain/partiter.h b/com32/chain/partiter.h
index d01a650..22c0e42 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_RELAX = 2, PIF_PREFMBR = 4};
+enum {PIF_STEPALL = 1, PIF_PREFMBR = 2, PIF_STRICT = 4, PIF_STRICTER = 8};
 
 struct itertype;
 struct part_iter;
diff --git a/doc/chain.txt b/doc/chain.txt
index 2321c10..effd508 100644
--- a/doc/chain.txt
+++ b/doc/chain.txt
@@ -160,6 +160,7 @@ useful to also fix its BPB values.
 
 	save
 	*nosave
+	save sets: strict=2
 
 Fixing BPB values only in memory might not be enough. This option allows
 writing of the corrected sector. You will probably want to use this option
@@ -195,6 +196,7 @@ drive we use during chainloading is not fd0 or hd0.
 	hide[all]
 	unhide[all]
 	*nohide
+	[un]hide[all] sets: strict=2
 
 In certain situations it's useful to hide partitions - for example to make sure
 DOS gets C:. 'hide' will hide hidable primary partitions, except the one we're
@@ -205,6 +207,7 @@ Writing is only performed, if the os type values actually changed.
 
 	fixchs
 	*nofixchs
+	fixchs sets: strict=2
 
 If you want to make a drive you're booting from totally compatible with current
 BIOS, you can use this to fix all partitions' CHS numbers. Good to silence e.g.
@@ -232,15 +235,23 @@ 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.
 
+	strict[=<0|1|2>]
+	*strict=1
 	relax
-	*norelax
-
-This option inhibits sanity checks during the traversal of the partition table.
-This is potentially useful in corner cases, when for example an usb stick moved
-to some different computer would report smaller size than previously with
-partitions spanning the whole space. Normally partition iterator would report
-an error and abort in such case. Another case scenario is disk corruption in
-some later EMBR partition.
+
+Those options control the level of sanity checks used during the traversal of
+partition table(s). This is useful in buggy corner cases, when the disk size is
+reported differently across different computers or virtual machines (if it
+happens at all, the size usually differs by 1 sector). Normally the partition
+iterator would report an error and abort in such case. Another case scenario is
+disk corruption in some later EMBR partition.
+
+- strict=0 inhibits any checks
+- strict=1 enables checks, but ignores those that involve disk size
+- strict=2 enables all checks
+- relax and nostrict are equivalent to strict=0
+- norelax and strict are equivalent to strict=2
+
 
 	break
 	*nobreak
-- 
1.7.10.4



More information about the Syslinux mailing list