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
This commit is contained in:
Eric Andersen 2004-09-02 23:13:10 +00:00
parent 7b08cdd98c
commit fd7a4c8c28

View File

@ -299,7 +299,7 @@ static int rlookup(char *n);
static struct wdblock *glob(char *cp, struct wdblock *wb); static struct wdblock *glob(char *cp, struct wdblock *wb);
static int my_getc(int ec); static int my_getc(int ec);
static int subgetc(int ec, int quoted); 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 char **eval(char **ap, int f);
static int setstatus(int s); static int setstatus(int s);
static int waitfor(int lastpid, int canintr); static int waitfor(int lastpid, int canintr);
@ -3032,7 +3032,7 @@ forkexec(REGISTER struct op *t, int *pin, int *pout, int act, char **wp)
if (wp[0] == NULL) if (wp[0] == NULL)
_exit(0); _exit(0);
cp = rexecve(wp[0], wp, makenv(0)); cp = rexecve(wp[0], wp, makenv(0, NULL));
prs(wp[0]); prs(wp[0]);
prs(": "); prs(": ");
err(cp); err(cp);
@ -3486,7 +3486,7 @@ struct op *t;
signal(SIGINT, SIG_DFL); signal(SIGINT, SIG_DFL);
signal(SIGQUIT, 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(t->words[0]);
prs(": "); prs(": ");
err(cp); err(cp);
@ -3954,14 +3954,12 @@ static char **eval(char **ap, int f)
* names in the dictionary. Keyword assignments * names in the dictionary. Keyword assignments
* will already have been done. * 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; REGISTER struct var *vp;
DBGPRINTF5(("MAKENV: enter, all=%d\n", all)); DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
wb = NULL;
for (vp = vlist; vp; vp = vp->next) for (vp = vlist; vp; vp = vp->next)
if (all || vp->status & EXPORT) if (all || vp->status & EXPORT)
wb = addword(vp->name, wb); wb = addword(vp->name, wb);
@ -4251,6 +4249,7 @@ int quoted;
int ignore; int ignore;
int ignore_once; int ignore_once;
char *argument_list[4]; char *argument_list[4];
struct wdblock *wb = NULL;
#if __GNUC__ #if __GNUC__
/* Avoid longjmp clobbering */ /* Avoid longjmp clobbering */
@ -4323,9 +4322,33 @@ int quoted;
src++; src++;
} }
if (isalpha(*var_name)) {
/* let subshell handle it instead */
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); vp = lookup(var_name);
if (vp->value != null) if (vp->value != null)
value = (operator == '+') ? alt_value : vp->value; value = (operator == '+') ?
alt_value : vp->value;
else if (operator == '?') { else if (operator == '?') {
err(alt_value); err(alt_value);
return (0); return (0);
@ -4340,6 +4363,7 @@ int quoted;
*dest++ = *value++; *dest++ = *value++;
count++; count++;
} }
}
} else { } else {
*dest++ = *src++; *dest++ = *src++;
count++; count++;
@ -4383,7 +4407,7 @@ int quoted;
argument_list[2] = child_cmd; argument_list[2] = child_cmd;
argument_list[3] = 0; 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(argument_list[0]);
prs(": "); prs(": ");
err(cp); err(cp);