Patchwork block: cmdline-parser: perfect cmdline format checking

login
register
mail settings
Submitter Caizhiyong
Date Nov. 9, 2013, 11:45 a.m.
Message ID <C3050A4DBA34F345975765E43127F10F1C08B3FB@szxeml512-mbs.china.huawei.com>
Download mbox | patch
Permalink /patch/289989/
State New
Headers show

Comments

Caizhiyong - Nov. 9, 2013, 11:45 a.m.
From: Cai Zhiyong <caizhiyong@huawei.com>
Date: Sat, 9 Nov 2013 19:27:38 +0800
Subject: [PATCH] block: cmdline-parser: perfect cmdline format checking

 -Fix compile warning with value and function undeclared.
  this reported by <fengguang.wu@intel.com> and
  Randy Dunlap <rdunlap@infradead.org>

 -perfect cmdline format checking, make the error information clear
  for understand, make this lib fully equivalent to the old parser
  in drivers/mtd/cmdlinepart.c

Signed-off-by: Cai Zhiyong <caizhiyong@huawei.com>
---
 block/cmdline-parser.c         | 86 +++++++++++++++++++++++++++++++-----------
 include/linux/cmdline-parser.h |  1 +
 2 files changed, 65 insertions(+), 22 deletions(-)

Patch

diff --git a/block/cmdline-parser.c b/block/cmdline-parser.c
index 9dbc67e..39b6cf4 100644
--- a/block/cmdline-parser.c
+++ b/block/cmdline-parser.c
@@ -6,10 +6,15 @@ 
  */
 #include <linux/export.h>
 #include <linux/cmdline-parser.h>
+#include <linux/slab.h>
+
+#define PARSER                       "cmdline-parser: "
 
 static int parse_subpart(struct cmdline_subpart **subpart, char *partdef)
 {
 	int ret = 0;
+	int lastpart = 0;
+	char *partorg = partdef;
 	struct cmdline_subpart *new_subpart;
 
 	*subpart = NULL;
@@ -21,10 +26,12 @@  static int parse_subpart(struct cmdline_subpart **subpart, char *partdef)
 	if (*partdef == '-') {
 		new_subpart->size = (sector_t)(~0ULL);
 		partdef++;
+		lastpart = 1;
 	} else {
 		new_subpart->size = (sector_t)memparse(partdef, &partdef);
 		if (new_subpart->size < (sector_t)PAGE_SIZE) {
-			pr_warn("cmdline partition size is invalid.");
+			pr_warn(PARSER "partition '%s' size '0x%llx' too small.",
+				partorg, new_subpart->size);
 			ret = -EINVAL;
 			goto fail;
 		}
@@ -42,13 +49,19 @@  static int parse_subpart(struct cmdline_subpart **subpart, char *partdef)
 		char *next = strchr(++partdef, ')');
 
 		if (!next) {
-			pr_warn("cmdline partition format is invalid.");
+			pr_warn(PARSER "partition '%s' has no closing ')' "
+				"found in partition name.", partorg);
 			ret = -EINVAL;
 			goto fail;
 		}
 
-		length = min_t(int, next - partdef,
-			       sizeof(new_subpart->name) - 1);
+		length = (int)(next - partdef);
+		if (length > sizeof(new_subpart->name) - 1) {
+			pr_warn(PARSER "partition '%s' partition name too long,"
+				" truncating.", partorg);
+			length = sizeof(new_subpart->name) - 1;
+		}
+
 		strncpy(new_subpart->name, partdef, length);
 		new_subpart->name[length] = '\0';
 
@@ -68,8 +81,15 @@  static int parse_subpart(struct cmdline_subpart **subpart, char *partdef)
 		partdef += 2;
 	}
 
+	if (*partdef) {
+		pr_warn(PARSER "partition '%s' has bad character '%c' after"
+			" partition.", partorg, *partdef);
+		ret = -EINVAL;
+		goto fail;
+	}
+
 	*subpart = new_subpart;
-	return 0;
+	return lastpart;
 fail:
 	kfree(new_subpart);
 	return ret;
@@ -86,14 +106,13 @@  static void free_subpart(struct cmdline_parts *parts)
 	}
 }
 
-static int parse_parts(struct cmdline_parts **parts, const char *bdevdef)
+static int parse_parts(struct cmdline_parts **parts, char *bdevdef)
 {
 	int ret = -EINVAL;
 	char *next;
 	int length;
 	struct cmdline_subpart **next_subpart;
 	struct cmdline_parts *newparts;
-	char buf[BDEVNAME_SIZE + 32 + 4];
 
 	*parts = NULL;
 
@@ -102,14 +121,21 @@  static int parse_parts(struct cmdline_parts **parts, const char *bdevdef)
 		return -ENOMEM;
 
 	next = strchr(bdevdef, ':');
-	if (!next) {
-		pr_warn("cmdline partition has no block device.");
+	if (!next || next == bdevdef) {
+		pr_warn(PARSER "partition '%s' has no block device.", bdevdef);
 		goto fail;
 	}
 
-	length = min_t(int, next - bdevdef, sizeof(newparts->name) - 1);
+	length = (int)(next - bdevdef);
+	if (length > sizeof(newparts->name) - 1) {
+		pr_warn(PARSER "partition '%s' device name too long, "
+			"truncating.", bdevdef);
+		length = sizeof(newparts->name) - 1;
+	}
+
 	strncpy(newparts->name, bdevdef, length);
 	newparts->name[length] = '\0';
+
 	newparts->nr_subparts = 0;
 
 	next_subpart = &newparts->subpart;
@@ -117,23 +143,26 @@  static int parse_parts(struct cmdline_parts **parts, const char *bdevdef)
 	while (next && *(++next)) {
 		bdevdef = next;
 		next = strchr(bdevdef, ',');
+		if (next)
+			*next = '\0';
 
-		length = (!next) ? (sizeof(buf) - 1) :
-			min_t(int, next - bdevdef, sizeof(buf) - 1);
-
-		strncpy(buf, bdevdef, length);
-		buf[length] = '\0';
-
-		ret = parse_subpart(next_subpart, buf);
-		if (ret)
+		ret = parse_subpart(next_subpart, bdevdef);
+		if (ret < 0) {
 			goto fail;
+		} else if (ret > 0 && next) {
+			pr_warn(PARSER "no partitions allowed after a "
+				"fill-up partition.");
+			ret = -EINVAL;
+			goto fail;
+		}
 
 		newparts->nr_subparts++;
 		next_subpart = &(*next_subpart)->next_subpart;
 	}
 
 	if (!newparts->subpart) {
-		pr_warn("cmdline partition has no valid partition.");
+		pr_warn(PARSER "block device '%s' has no valid"
+			" partition.", newparts->name);
 		ret = -EINVAL;
 		goto fail;
 	}
@@ -192,7 +221,7 @@  int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline)
 	}
 
 	if (!*parts) {
-		pr_warn("cmdline partition has no valid partition.");
+		pr_warn(PARSER "no found valid partition.");
 		ret = -EINVAL;
 		goto fail;
 	}
@@ -237,11 +266,24 @@  int cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
 		else
 			from = subpart->from;
 
-		if (from >= disk_size)
+		if (subpart->name[0] == '\0')
+			snprintf(subpart->name, sizeof(subpart->name),
+				 "partition%03d", slot);
+
+		if (from >= disk_size) {
+			pr_warn(PARSER "partition '%s' offset exceeds device"
+				" '%s' size '0x%llx', ignoring.",
+				subpart->name, parts->name, disk_size);
 			break;
+		}
 
-		if (subpart->size > (disk_size - from))
+		if (subpart->size > (disk_size - from)) {
+			if (subpart->size != (sector_t)(~0ULL))
+				pr_warn(PARSER "partition '%s' size exceeds "
+					"device '%s' size '0x%llx', truncating.",
+					subpart->name, parts->name, disk_size);
 			subpart->size = disk_size - from;
+		}
 
 		from += subpart->size;
 
diff --git a/include/linux/cmdline-parser.h b/include/linux/cmdline-parser.h
index 43b65a9..c6491b2 100644
--- a/include/linux/cmdline-parser.h
+++ b/include/linux/cmdline-parser.h
@@ -8,6 +8,7 @@ 
 #define CMDLINEPARSEH
 
 #include <linux/blkdev.h>
+#include <linux/fs.h>
 
 /* partition flags */
 #define PF_RDONLY                   0x01 /* Device is read only */