hush: fix a memory corruption when exported variable is modified

The construct such as this:

t=1
export t
t=new_value1

had a small probability of momentarily using free()d value.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko
2016-10-03 15:01:06 +02:00
parent 04465dad66
commit a769390da6

View File

@@ -1891,6 +1891,7 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_
{ {
struct variable **var_pp; struct variable **var_pp;
struct variable *cur; struct variable *cur;
char *free_me = NULL;
char *eq_sign; char *eq_sign;
int name_len; int name_len;
@@ -1907,6 +1908,7 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_
var_pp = &cur->next; var_pp = &cur->next;
continue; continue;
} }
/* We found an existing var with this name */ /* We found an existing var with this name */
if (cur->flg_read_only) { if (cur->flg_read_only) {
#if !BB_MMU #if !BB_MMU
@@ -1955,12 +1957,17 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_
strcpy(cur->varstr, str); strcpy(cur->varstr, str);
goto free_and_exp; goto free_and_exp;
} }
} else { /* Can't reuse */
/* max_len == 0 signifies "malloced" var, which we can cur->max_len = 0;
* (and has to) free */ goto set_str_and_exp;
free(cur->varstr);
} }
cur->max_len = 0; /* max_len == 0 signifies "malloced" var, which we can
* (and have to) free. But we can't free(cur->varstr) here:
* if cur->flg_export is 1, it is in the environment.
* We should either unsetenv+free, or wait until putenv,
* then putenv(new)+free(old).
*/
free_me = cur->varstr;
goto set_str_and_exp; goto set_str_and_exp;
} }
@@ -1987,10 +1994,15 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_
cur->flg_export = 0; cur->flg_export = 0;
/* unsetenv was already done */ /* unsetenv was already done */
} else { } else {
int i;
debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr); debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr);
return putenv(cur->varstr); i = putenv(cur->varstr);
/* only now we can free old exported malloced string */
free(free_me);
return i;
} }
} }
free(free_me);
return 0; return 0;
} }