[U-Boot] [PATCH 3/4] bootm: Avoid 256-byte overflow in fixup_silent_linux()

Doug Anderson dianders at chromium.org
Thu Oct 20 00:30:58 CEST 2011


This makes fixup_silent_linux() use malloc() to allocate its
working space, meaning that our maximum kernel command line
should only be limited by malloc().  Previously it was silently
overflowing the stack.

Signed-off-by: Doug Anderson <dianders at chromium.org>
---
 common/cmd_bootm.c |  125 ++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 106 insertions(+), 19 deletions(-)

diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index ece1b9a..f426e2f 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -26,6 +26,7 @@
  * Boot support
  */
 #include <common.h>
+#include <cmdline.h>
 #include <watchdog.h>
 #include <command.h>
 #include <image.h>
@@ -1200,36 +1201,122 @@ U_BOOT_CMD(
 /* helper routines */
 /*******************************************************************/
 #ifdef CONFIG_SILENT_CONSOLE
+
+/**
+ * Remove "console=blah" and from cmdline, replace w/ "console=".
+ *
+ * This has the effect of telling Linux that we'd like it to have a silent
+ * console.
+ *
+ * @param cmdline	The original commanjd line.
+ * @return The new command line, which has been allocated with malloc().
+ *	   Might be NULL if we ran out of memory.
+ */
+static char *do_fixup_silent_linux(const char *cmdline)
+{
+	char *buf;
+	int bufsize;
+	int did_remove;
+
+	if (!cmdline)
+		cmdline = "";
+
+	/*
+	 * Allocate enough space for:
+	 * - a copy of the command line
+	 * - a space
+	 * - a blank "console=" argument
+	 * - the '\0'
+	 *
+	 * ...we might not need all this space, but it's OK to overallocate a
+	 * little.
+	 */
+	bufsize = strlen(cmdline) + 1 + sizeof("console=");
+	buf = malloc(bufsize);
+	if (!buf) {
+		debug("WARNING: malloc failed in fixup_silent_linux\n");
+		return NULL;
+	}
+
+	strcpy(buf, cmdline);
+	do {
+		did_remove  = remove_cmdline_param(buf, "console");
+	} while (did_remove);
+	add_cmdline_param(buf, "console=", bufsize);
+
+	return buf;
+}
+
 static void fixup_silent_linux(void)
 {
-	char buf[256], *start, *end;
-	char *cmdline = getenv("bootargs");
+	char *buf;
+	const char *cmdline = getenv("bootargs");
 
 	/* Only fix cmdline when requested */
 	if (!(gd->flags & GD_FLG_SILENT))
 		return;
 
 	debug("before silent fix-up: %s\n", cmdline);
-	if (cmdline) {
-		start = strstr(cmdline, "console=");
-		if (start) {
-			end = strchr(start, ' ');
-			strncpy(buf, cmdline, (start - cmdline + 8));
-			if (end)
-				strcpy(buf + (start - cmdline + 8), end);
-			else
-				buf[start - cmdline + 8] = '\0';
-		} else {
-			strcpy(buf, cmdline);
-			strcat(buf, " console=");
-		}
-	} else {
-		strcpy(buf, "console=");
+
+	buf = do_fixup_silent_linux(cmdline);
+	if (buf) {
+		setenv("bootargs", buf);
+		debug("after silent fix-up: %s\n", buf);
+		free(buf);
 	}
+}
 
-	setenv("bootargs", buf);
-	debug("after silent fix-up: %s\n", buf);
+/**
+ * Unit tests for do_fixup_silent_linux().
+ *
+ * At the moment, there's no easy way to run this other than to copy it (and
+ * do_fixup_silent_linux) to another file.
+ */
+#ifdef RUN_UNITTESTS
+void do_fixup_silent_linux_unittest(void)
+{
+	char *original_str;
+	char *expected_str;
+	char *result;
+
+	/* Simple case first, as an example */
+	original_str = "console=ttyS0,115200n8 root=/dev/mmcblk0p3 rootwait ro";
+	expected_str = "root=/dev/mmcblk0p3 rootwait ro console=";
+	result = do_fixup_silent_linux(original_str);
+	assert(strcmp(result, expected_str) == 0);
+	free(result);
+
+	/* Null cases next */
+	original_str = NULL;
+	expected_str = "console=";
+	result = do_fixup_silent_linux(original_str);
+	assert(strcmp(result, expected_str) == 0);
+	free(result);
+
+	original_str = "";
+	expected_str = "console=";
+	result = do_fixup_silent_linux(original_str);
+	assert(strcmp(result, expected_str) == 0);
+	free(result);
+
+	/* Throw console= at the end */
+	original_str = "root=/dev/mmcblk0p3 rootwait ro console=ttyS0,115200n8";
+	expected_str = "root=/dev/mmcblk0p3 rootwait ro console=";
+	result = do_fixup_silent_linux(original_str);
+	assert(strcmp(result, expected_str) == 0);
+	free(result);
+
+	/* Something non-NULL with no "console=" */
+	original_str = "root=/dev/mmcblk0p3 rootwait ro";
+	expected_str = "root=/dev/mmcblk0p3 rootwait ro console=";
+	result = do_fixup_silent_linux(original_str);
+	assert(strcmp(result, expected_str) == 0);
+	free(result);
+
+	debug("do_fixup_silent_linux_unittest: pass\n");
 }
+#endif /* RUN_UNITTESTS */
+
 #endif /* CONFIG_SILENT_CONSOLE */
 
 
-- 
1.7.3.1



More information about the U-Boot mailing list