diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-03 15:01:06 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-03 15:01:06 +0200 |
commit | a769390da604b4815535e296d8a46fdf9094c2c7 (patch) | |
tree | 9317c96f494de0a2a8f026272fd541ed245c2ec3 | |
parent | 04465dad66478aea28100ff5b9094d1c02336f07 (diff) | |
download | busybox-w32-a769390da604b4815535e296d8a46fdf9094c2c7.tar.gz busybox-w32-a769390da604b4815535e296d8a46fdf9094c2c7.tar.bz2 busybox-w32-a769390da604b4815535e296d8a46fdf9094c2c7.zip |
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>
-rw-r--r-- | shell/hush.c | 26 |
1 files changed, 19 insertions, 7 deletions
diff --git a/shell/hush.c b/shell/hush.c index d0d983018..668b1f2b7 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -1891,6 +1891,7 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_ | |||
1891 | { | 1891 | { |
1892 | struct variable **var_pp; | 1892 | struct variable **var_pp; |
1893 | struct variable *cur; | 1893 | struct variable *cur; |
1894 | char *free_me = NULL; | ||
1894 | char *eq_sign; | 1895 | char *eq_sign; |
1895 | int name_len; | 1896 | int name_len; |
1896 | 1897 | ||
@@ -1907,6 +1908,7 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_ | |||
1907 | var_pp = &cur->next; | 1908 | var_pp = &cur->next; |
1908 | continue; | 1909 | continue; |
1909 | } | 1910 | } |
1911 | |||
1910 | /* We found an existing var with this name */ | 1912 | /* We found an existing var with this name */ |
1911 | if (cur->flg_read_only) { | 1913 | if (cur->flg_read_only) { |
1912 | #if !BB_MMU | 1914 | #if !BB_MMU |
@@ -1955,12 +1957,17 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_ | |||
1955 | strcpy(cur->varstr, str); | 1957 | strcpy(cur->varstr, str); |
1956 | goto free_and_exp; | 1958 | goto free_and_exp; |
1957 | } | 1959 | } |
1958 | } else { | 1960 | /* Can't reuse */ |
1959 | /* max_len == 0 signifies "malloced" var, which we can | 1961 | cur->max_len = 0; |
1960 | * (and has to) free */ | 1962 | goto set_str_and_exp; |
1961 | free(cur->varstr); | 1963 | } |
1962 | } | 1964 | /* max_len == 0 signifies "malloced" var, which we can |
1963 | cur->max_len = 0; | 1965 | * (and have to) free. But we can't free(cur->varstr) here: |
1966 | * if cur->flg_export is 1, it is in the environment. | ||
1967 | * We should either unsetenv+free, or wait until putenv, | ||
1968 | * then putenv(new)+free(old). | ||
1969 | */ | ||
1970 | free_me = cur->varstr; | ||
1964 | goto set_str_and_exp; | 1971 | goto set_str_and_exp; |
1965 | } | 1972 | } |
1966 | 1973 | ||
@@ -1987,10 +1994,15 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_ | |||
1987 | cur->flg_export = 0; | 1994 | cur->flg_export = 0; |
1988 | /* unsetenv was already done */ | 1995 | /* unsetenv was already done */ |
1989 | } else { | 1996 | } else { |
1997 | int i; | ||
1990 | debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr); | 1998 | debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr); |
1991 | return putenv(cur->varstr); | 1999 | i = putenv(cur->varstr); |
2000 | /* only now we can free old exported malloced string */ | ||
2001 | free(free_me); | ||
2002 | return i; | ||
1992 | } | 2003 | } |
1993 | } | 2004 | } |
2005 | free(free_me); | ||
1994 | return 0; | 2006 | return 0; |
1995 | } | 2007 | } |
1996 | 2008 | ||