Jonas Holmberg from axis dot com writes:

This patch makes msh handle variable expansion within backticks more
correctly.

Current behaviour (wrong):
--------------------------

BusyBox v1.00-rc3 (2004.08.26-11:51+0000) Built-in shell (msh)
Enter 'help' for a list of built-in commands.

$ A='`echo hello`'
$ echo $A
`echo hello`
$ echo `echo $A`
hello
$


New behaviour (correct):
------------------------

BusyBox v1.00-rc3 (2004.08.26-11:51+0000) Built-in shell (msh)
Enter 'help' for a list of built-in commands.

$ A='`echo hello`'
$ echo $A
`echo hello`
$ echo `echo $A`
`echo hello`
$

The current behaviour (wrong according to standards) was actually my
fault. msh handles backticks by executing a subshell (which makes it
work on MMU-less systems). Executing a subshell makes it hard to only
expand variables once in the parent. Therefore I export all variables
that will be expanded within the backticks and let the subshell handle
the expansion instead.

The bug was found while searching for security leaks in CGI-scripts.
Current behaviour of msh makes it easy to expand backticks by mistake
in $QUERY_STRING. I recommend appling the patch before release of bb
1.00.

/Jonas
diff --git a/shell/msh.c b/shell/msh.c
index df4c3da..2fb0df7 100644
--- a/shell/msh.c
+++ b/shell/msh.c
@@ -299,7 +299,7 @@
 static struct wdblock *glob(char *cp, struct wdblock *wb);
 static int my_getc(int ec);
 static int subgetc(int ec, int quoted);
-static char **makenv(int all);
+static char **makenv(int all, struct wdblock *wb);
 static char **eval(char **ap, int f);
 static int setstatus(int s);
 static int waitfor(int lastpid, int canintr);
@@ -3032,7 +3032,7 @@
 	if (wp[0] == NULL)
 		_exit(0);
 
-	cp = rexecve(wp[0], wp, makenv(0));
+	cp = rexecve(wp[0], wp, makenv(0, NULL));
 	prs(wp[0]);
 	prs(": ");
 	err(cp);
@@ -3486,7 +3486,7 @@
 		signal(SIGINT, SIG_DFL);
 		signal(SIGQUIT, SIG_DFL);
 	}
-	cp = rexecve(t->words[0], t->words, makenv(0));
+	cp = rexecve(t->words[0], t->words, makenv(0, NULL));
 	prs(t->words[0]);
 	prs(": ");
 	err(cp);
@@ -3954,14 +3954,12 @@
  * names in the dictionary. Keyword assignments
  * will already have been done.
  */
-static char **makenv(int all)
+static char **makenv(int all, struct wdblock *wb)
 {
-	REGISTER struct wdblock *wb;
 	REGISTER struct var *vp;
 
 	DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
 
-	wb = NULL;
 	for (vp = vlist; vp; vp = vp->next)
 		if (all || vp->status & EXPORT)
 			wb = addword(vp->name, wb);
@@ -4251,6 +4249,7 @@
 	int ignore;
 	int ignore_once;
 	char *argument_list[4];
+	struct wdblock *wb = NULL;
 
 #if __GNUC__
 	/* Avoid longjmp clobbering */
@@ -4323,22 +4322,47 @@
 				src++;
 			}
 
-			vp = lookup(var_name);
-			if (vp->value != null)
-				value = (operator == '+') ? alt_value : vp->value;
-			else if (operator == '?') {
-				err(alt_value);
-				return (0);
-			} else if (alt_index && (operator != '+')) {
-				value = alt_value;
-				if (operator == '=')
-					setval(vp, value);
-			} else
-				continue;
+			if (isalpha(*var_name)) {
+				/* let subshell handle it instead */
 
-			while (*value && (count < LINELIM)) {
-				*dest++ = *value++;
-				count++;
+				char *namep = var_name;
+
+				*dest++ = '$';
+				if (braces)
+					*dest++ = '{';
+				while (*namep)
+					*dest++ = *namep++;
+				if (operator) {
+					char *altp = alt_value;
+					*dest++ = operator;
+					while (*altp)
+						*dest++ = *altp++;
+				}
+				if (braces)
+					*dest++ = '}';
+
+				wb = addword(lookup(var_name)->name, wb);
+			} else {
+				/* expand */
+
+				vp = lookup(var_name);
+				if (vp->value != null)
+					value = (operator == '+') ?
+						alt_value : vp->value;
+				else if (operator == '?') {
+					err(alt_value);
+					return (0);
+				} else if (alt_index && (operator != '+')) {
+					value = alt_value;
+					if (operator == '=')
+						setval(vp, value);
+				} else
+					continue;
+
+				while (*value && (count < LINELIM)) {
+					*dest++ = *value++;
+					count++;
+				}
 			}
 		} else {
 			*dest++ = *src++;
@@ -4383,7 +4407,7 @@
 	argument_list[2] = child_cmd;
 	argument_list[3] = 0;
 
-	cp = rexecve(argument_list[0], argument_list, makenv(1));
+	cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
 	prs(argument_list[0]);
 	prs(": ");
 	err(cp);