diff options
author | Eric Andersen <andersen@codepoet.org> | 2004-09-02 23:13:10 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2004-09-02 23:13:10 +0000 |
commit | fd7a4c8c2887187e901809d89997deefb8b99d97 (patch) | |
tree | 70ea04a5934546b070f3e0c403629fe4da7aa444 | |
parent | 7b08cdd98cdf99b0d2bd622566e9288d44b17529 (diff) | |
download | busybox-w32-fd7a4c8c2887187e901809d89997deefb8b99d97.tar.gz busybox-w32-fd7a4c8c2887187e901809d89997deefb8b99d97.tar.bz2 busybox-w32-fd7a4c8c2887187e901809d89997deefb8b99d97.zip |
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
-rw-r--r-- | shell/msh.c | 68 |
1 files changed, 46 insertions, 22 deletions
diff --git a/shell/msh.c b/shell/msh.c index df4c3dab3..2fb0df739 100644 --- a/shell/msh.c +++ b/shell/msh.c | |||
@@ -299,7 +299,7 @@ static int rlookup(char *n); | |||
299 | static struct wdblock *glob(char *cp, struct wdblock *wb); | 299 | static struct wdblock *glob(char *cp, struct wdblock *wb); |
300 | static int my_getc(int ec); | 300 | static int my_getc(int ec); |
301 | static int subgetc(int ec, int quoted); | 301 | static int subgetc(int ec, int quoted); |
302 | static char **makenv(int all); | 302 | static char **makenv(int all, struct wdblock *wb); |
303 | static char **eval(char **ap, int f); | 303 | static char **eval(char **ap, int f); |
304 | static int setstatus(int s); | 304 | static int setstatus(int s); |
305 | static int waitfor(int lastpid, int canintr); | 305 | static int waitfor(int lastpid, int canintr); |
@@ -3032,7 +3032,7 @@ forkexec(REGISTER struct op *t, int *pin, int *pout, int act, char **wp) | |||
3032 | if (wp[0] == NULL) | 3032 | if (wp[0] == NULL) |
3033 | _exit(0); | 3033 | _exit(0); |
3034 | 3034 | ||
3035 | cp = rexecve(wp[0], wp, makenv(0)); | 3035 | cp = rexecve(wp[0], wp, makenv(0, NULL)); |
3036 | prs(wp[0]); | 3036 | prs(wp[0]); |
3037 | prs(": "); | 3037 | prs(": "); |
3038 | err(cp); | 3038 | err(cp); |
@@ -3486,7 +3486,7 @@ struct op *t; | |||
3486 | signal(SIGINT, SIG_DFL); | 3486 | signal(SIGINT, SIG_DFL); |
3487 | signal(SIGQUIT, SIG_DFL); | 3487 | signal(SIGQUIT, SIG_DFL); |
3488 | } | 3488 | } |
3489 | cp = rexecve(t->words[0], t->words, makenv(0)); | 3489 | cp = rexecve(t->words[0], t->words, makenv(0, NULL)); |
3490 | prs(t->words[0]); | 3490 | prs(t->words[0]); |
3491 | prs(": "); | 3491 | prs(": "); |
3492 | err(cp); | 3492 | err(cp); |
@@ -3954,14 +3954,12 @@ static char **eval(char **ap, int f) | |||
3954 | * names in the dictionary. Keyword assignments | 3954 | * names in the dictionary. Keyword assignments |
3955 | * will already have been done. | 3955 | * will already have been done. |
3956 | */ | 3956 | */ |
3957 | static char **makenv(int all) | 3957 | static char **makenv(int all, struct wdblock *wb) |
3958 | { | 3958 | { |
3959 | REGISTER struct wdblock *wb; | ||
3960 | REGISTER struct var *vp; | 3959 | REGISTER struct var *vp; |
3961 | 3960 | ||
3962 | DBGPRINTF5(("MAKENV: enter, all=%d\n", all)); | 3961 | DBGPRINTF5(("MAKENV: enter, all=%d\n", all)); |
3963 | 3962 | ||
3964 | wb = NULL; | ||
3965 | for (vp = vlist; vp; vp = vp->next) | 3963 | for (vp = vlist; vp; vp = vp->next) |
3966 | if (all || vp->status & EXPORT) | 3964 | if (all || vp->status & EXPORT) |
3967 | wb = addword(vp->name, wb); | 3965 | wb = addword(vp->name, wb); |
@@ -4251,6 +4249,7 @@ int quoted; | |||
4251 | int ignore; | 4249 | int ignore; |
4252 | int ignore_once; | 4250 | int ignore_once; |
4253 | char *argument_list[4]; | 4251 | char *argument_list[4]; |
4252 | struct wdblock *wb = NULL; | ||
4254 | 4253 | ||
4255 | #if __GNUC__ | 4254 | #if __GNUC__ |
4256 | /* Avoid longjmp clobbering */ | 4255 | /* Avoid longjmp clobbering */ |
@@ -4323,22 +4322,47 @@ int quoted; | |||
4323 | src++; | 4322 | src++; |
4324 | } | 4323 | } |
4325 | 4324 | ||
4326 | vp = lookup(var_name); | 4325 | if (isalpha(*var_name)) { |
4327 | if (vp->value != null) | 4326 | /* let subshell handle it instead */ |
4328 | value = (operator == '+') ? alt_value : vp->value; | 4327 | |
4329 | else if (operator == '?') { | 4328 | char *namep = var_name; |
4330 | err(alt_value); | ||
4331 | return (0); | ||
4332 | } else if (alt_index && (operator != '+')) { | ||
4333 | value = alt_value; | ||
4334 | if (operator == '=') | ||
4335 | setval(vp, value); | ||
4336 | } else | ||
4337 | continue; | ||
4338 | 4329 | ||
4339 | while (*value && (count < LINELIM)) { | 4330 | *dest++ = '$'; |
4340 | *dest++ = *value++; | 4331 | if (braces) |
4341 | count++; | 4332 | *dest++ = '{'; |
4333 | while (*namep) | ||
4334 | *dest++ = *namep++; | ||
4335 | if (operator) { | ||
4336 | char *altp = alt_value; | ||
4337 | *dest++ = operator; | ||
4338 | while (*altp) | ||
4339 | *dest++ = *altp++; | ||
4340 | } | ||
4341 | if (braces) | ||
4342 | *dest++ = '}'; | ||
4343 | |||
4344 | wb = addword(lookup(var_name)->name, wb); | ||
4345 | } else { | ||
4346 | /* expand */ | ||
4347 | |||
4348 | vp = lookup(var_name); | ||
4349 | if (vp->value != null) | ||
4350 | value = (operator == '+') ? | ||
4351 | alt_value : vp->value; | ||
4352 | else if (operator == '?') { | ||
4353 | err(alt_value); | ||
4354 | return (0); | ||
4355 | } else if (alt_index && (operator != '+')) { | ||
4356 | value = alt_value; | ||
4357 | if (operator == '=') | ||
4358 | setval(vp, value); | ||
4359 | } else | ||
4360 | continue; | ||
4361 | |||
4362 | while (*value && (count < LINELIM)) { | ||
4363 | *dest++ = *value++; | ||
4364 | count++; | ||
4365 | } | ||
4342 | } | 4366 | } |
4343 | } else { | 4367 | } else { |
4344 | *dest++ = *src++; | 4368 | *dest++ = *src++; |
@@ -4383,7 +4407,7 @@ int quoted; | |||
4383 | argument_list[2] = child_cmd; | 4407 | argument_list[2] = child_cmd; |
4384 | argument_list[3] = 0; | 4408 | argument_list[3] = 0; |
4385 | 4409 | ||
4386 | cp = rexecve(argument_list[0], argument_list, makenv(1)); | 4410 | cp = rexecve(argument_list[0], argument_list, makenv(1, wb)); |
4387 | prs(argument_list[0]); | 4411 | prs(argument_list[0]); |
4388 | prs(": "); | 4412 | prs(": "); |
4389 | err(cp); | 4413 | err(cp); |