Signed-off-by: Marcel Denia <naoir@gmx.net>lilik-openwrt-22.03
@ -0,0 +1,176 @@ | |||||
BASH PATCH REPORT | |||||
================= | |||||
Bash-Release: 4.3 | |||||
Patch-ID: bash43-027 | |||||
Bug-Reported-by: Florian Weimer <fweimer@redhat.com> | |||||
Bug-Reference-ID: | |||||
Bug-Reference-URL: | |||||
Bug-Description: | |||||
This patch changes the encoding bash uses for exported functions to avoid | |||||
clashes with shell variables and to avoid depending only on an environment | |||||
variable's contents to determine whether or not to interpret it as a shell | |||||
function. | |||||
Patch (apply with `patch -p0'): | |||||
--- a/variables.c | |||||
+++ b/variables.c | |||||
@@ -83,6 +83,11 @@ | |||||
#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0') | |||||
+#define BASHFUNC_PREFIX "BASH_FUNC_" | |||||
+#define BASHFUNC_PREFLEN 10 /* == strlen(BASHFUNC_PREFIX */ | |||||
+#define BASHFUNC_SUFFIX "%%" | |||||
+#define BASHFUNC_SUFFLEN 2 /* == strlen(BASHFUNC_SUFFIX) */ | |||||
+ | |||||
extern char **environ; | |||||
/* Variables used here and defined in other files. */ | |||||
@@ -279,7 +284,7 @@ static void push_temp_var __P((PTR_T)); | |||||
static void propagate_temp_var __P((PTR_T)); | |||||
static void dispose_temporary_env __P((sh_free_func_t *)); | |||||
-static inline char *mk_env_string __P((const char *, const char *)); | |||||
+static inline char *mk_env_string __P((const char *, const char *, int)); | |||||
static char **make_env_array_from_var_list __P((SHELL_VAR **)); | |||||
static char **make_var_export_array __P((VAR_CONTEXT *)); | |||||
static char **make_func_export_array __P((void)); | |||||
@@ -349,22 +354,33 @@ initialize_shell_variables (env, privmod | |||||
/* If exported function, define it now. Don't import functions from | |||||
the environment in privileged mode. */ | |||||
- if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4)) | |||||
+ if (privmode == 0 && read_but_dont_execute == 0 && | |||||
+ STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) && | |||||
+ STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) && | |||||
+ STREQN ("() {", string, 4)) | |||||
{ | |||||
+ size_t namelen; | |||||
+ char *tname; /* desired imported function name */ | |||||
+ | |||||
+ namelen = char_index - BASHFUNC_PREFLEN - BASHFUNC_SUFFLEN; | |||||
+ | |||||
+ tname = name + BASHFUNC_PREFLEN; /* start of func name */ | |||||
+ tname[namelen] = '\0'; /* now tname == func name */ | |||||
+ | |||||
string_length = strlen (string); | |||||
- temp_string = (char *)xmalloc (3 + string_length + char_index); | |||||
+ temp_string = (char *)xmalloc (namelen + string_length + 2); | |||||
- strcpy (temp_string, name); | |||||
- temp_string[char_index] = ' '; | |||||
- strcpy (temp_string + char_index + 1, string); | |||||
+ memcpy (temp_string, tname, namelen); | |||||
+ temp_string[namelen] = ' '; | |||||
+ memcpy (temp_string + namelen + 1, string, string_length + 1); | |||||
/* Don't import function names that are invalid identifiers from the | |||||
environment, though we still allow them to be defined as shell | |||||
variables. */ | |||||
- if (legal_identifier (name)) | |||||
- parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD); | |||||
+ if (absolute_program (tname) == 0 && (posixly_correct == 0 || legal_identifier (tname))) | |||||
+ parse_and_execute (temp_string, tname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD); | |||||
- if (temp_var = find_function (name)) | |||||
+ if (temp_var = find_function (tname)) | |||||
{ | |||||
VSETATTR (temp_var, (att_exported|att_imported)); | |||||
array_needs_making = 1; | |||||
@@ -377,8 +393,11 @@ initialize_shell_variables (env, privmod | |||||
array_needs_making = 1; | |||||
} | |||||
last_command_exit_value = 1; | |||||
- report_error (_("error importing function definition for `%s'"), name); | |||||
+ report_error (_("error importing function definition for `%s'"), tname); | |||||
} | |||||
+ | |||||
+ /* Restore original suffix */ | |||||
+ tname[namelen] = BASHFUNC_SUFFIX[0]; | |||||
} | |||||
#if defined (ARRAY_VARS) | |||||
# if ARRAY_EXPORT | |||||
@@ -2954,7 +2973,7 @@ assign_in_env (word, flags) | |||||
var->context = variable_context; /* XXX */ | |||||
INVALIDATE_EXPORTSTR (var); | |||||
- var->exportstr = mk_env_string (name, value); | |||||
+ var->exportstr = mk_env_string (name, value, 0); | |||||
array_needs_making = 1; | |||||
@@ -3852,21 +3871,42 @@ merge_temporary_env () | |||||
/* **************************************************************** */ | |||||
static inline char * | |||||
-mk_env_string (name, value) | |||||
+mk_env_string (name, value, isfunc) | |||||
const char *name, *value; | |||||
+ int isfunc; | |||||
{ | |||||
- int name_len, value_len; | |||||
- char *p; | |||||
+ size_t name_len, value_len; | |||||
+ char *p, *q; | |||||
name_len = strlen (name); | |||||
value_len = STRLEN (value); | |||||
- p = (char *)xmalloc (2 + name_len + value_len); | |||||
- strcpy (p, name); | |||||
- p[name_len] = '='; | |||||
+ | |||||
+ /* If we are exporting a shell function, construct the encoded function | |||||
+ name. */ | |||||
+ if (isfunc && value) | |||||
+ { | |||||
+ p = (char *)xmalloc (BASHFUNC_PREFLEN + name_len + BASHFUNC_SUFFLEN + value_len + 2); | |||||
+ q = p; | |||||
+ memcpy (q, BASHFUNC_PREFIX, BASHFUNC_PREFLEN); | |||||
+ q += BASHFUNC_PREFLEN; | |||||
+ memcpy (q, name, name_len); | |||||
+ q += name_len; | |||||
+ memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN); | |||||
+ q += BASHFUNC_SUFFLEN; | |||||
+ } | |||||
+ else | |||||
+ { | |||||
+ p = (char *)xmalloc (2 + name_len + value_len); | |||||
+ memcpy (p, name, name_len); | |||||
+ q = p + name_len; | |||||
+ } | |||||
+ | |||||
+ q[0] = '='; | |||||
if (value && *value) | |||||
- strcpy (p + name_len + 1, value); | |||||
+ memcpy (q + 1, value, value_len + 1); | |||||
else | |||||
- p[name_len + 1] = '\0'; | |||||
+ q[1] = '\0'; | |||||
+ | |||||
return (p); | |||||
} | |||||
@@ -3952,7 +3992,7 @@ make_env_array_from_var_list (vars) | |||||
/* Gee, I'd like to get away with not using savestring() if we're | |||||
using the cached exportstr... */ | |||||
list[list_index] = USE_EXPORTSTR ? savestring (value) | |||||
- : mk_env_string (var->name, value); | |||||
+ : mk_env_string (var->name, value, function_p (var)); | |||||
if (USE_EXPORTSTR == 0) | |||||
SAVE_EXPORTSTR (var, list[list_index]); | |||||
--- a/patchlevel.h | |||||
+++ b/patchlevel.h | |||||
@@ -25,6 +25,6 @@ | |||||
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh | |||||
looks for to find the patch level (for the sccs version string). */ | |||||
-#define PATCHLEVEL 26 | |||||
+#define PATCHLEVEL 27 | |||||
#endif /* _PATCHLEVEL_H_ */ |
@ -0,0 +1,50 @@ | |||||
BASH PATCH REPORT | |||||
================= | |||||
Bash-Release: 4.3 | |||||
Patch-ID: bash43-029 | |||||
Bug-Reported-by: Michal Zalewski <lcamtuf@coredump.cx> | |||||
Bug-Reference-ID: | |||||
Bug-Reference-URL: | |||||
Bug-Description: | |||||
When bash is parsing a function definition that contains a here-document | |||||
delimited by end-of-file (or end-of-string), it leaves the closing delimiter | |||||
uninitialized. This can result in an invalid memory access when the parsed | |||||
function is later copied. | |||||
Patch (apply with `patch -p0'): | |||||
--- a/make_cmd.c | |||||
+++ b/make_cmd.c | |||||
@@ -692,6 +692,7 @@ make_redirection (source, instruction, d | |||||
/* First do the common cases. */ | |||||
temp->redirector = source; | |||||
temp->redirectee = dest_and_filename; | |||||
+ temp->here_doc_eof = 0; | |||||
temp->instruction = instruction; | |||||
temp->flags = 0; | |||||
temp->rflags = flags; | |||||
--- a/copy_cmd.c | |||||
+++ b/copy_cmd.c | |||||
@@ -126,7 +126,7 @@ copy_redirect (redirect) | |||||
{ | |||||
case r_reading_until: | |||||
case r_deblank_reading_until: | |||||
- new_redirect->here_doc_eof = savestring (redirect->here_doc_eof); | |||||
+ new_redirect->here_doc_eof = redirect->here_doc_eof ? savestring (redirect->here_doc_eof) : 0; | |||||
/*FALLTHROUGH*/ | |||||
case r_reading_string: | |||||
case r_appending_to: | |||||
--- a/patchlevel.h | |||||
+++ b/patchlevel.h | |||||
@@ -25,6 +25,6 @@ | |||||
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh | |||||
looks for to find the patch level (for the sccs version string). */ | |||||
-#define PATCHLEVEL 28 | |||||
+#define PATCHLEVEL 29 | |||||
#endif /* _PATCHLEVEL_H_ */ |
@ -1,83 +0,0 @@ | |||||
--- a/parse.y | |||||
+++ b/parse.y | |||||
@@ -265,9 +265,21 @@ int parser_state; | |||||
/* Variables to manage the task of reading here documents, because we need to | |||||
defer the reading until after a complete command has been collected. */ | |||||
-static REDIRECT *redir_stack[10]; | |||||
+static REDIRECT **redir_stack; | |||||
int need_here_doc; | |||||
+/* Pushes REDIR onto redir_stack, resizing it as needed. */ | |||||
+static void | |||||
+push_redir_stack (REDIRECT *redir) | |||||
+{ | |||||
+ /* Guard against oveflow. */ | |||||
+ if (need_here_doc + 1 > INT_MAX / sizeof (*redir_stack)) | |||||
+ abort (); | |||||
+ redir_stack = xrealloc (redir_stack, | |||||
+ (need_here_doc + 1) * sizeof (*redir_stack)); | |||||
+ redir_stack[need_here_doc++] = redir; | |||||
+} | |||||
+ | |||||
/* Where shell input comes from. History expansion is performed on each | |||||
line when the shell is interactive. */ | |||||
static char *shell_input_line = (char *)NULL; | |||||
@@ -520,42 +532,42 @@ redirection: '>' WORD | |||||
source.dest = 0; | |||||
redir.filename = $2; | |||||
$$ = make_redirection (source, r_reading_until, redir, 0); | |||||
- redir_stack[need_here_doc++] = $$; | |||||
+ push_redir_stack ($$); | |||||
} | |||||
| NUMBER LESS_LESS WORD | |||||
{ | |||||
source.dest = $1; | |||||
redir.filename = $3; | |||||
$$ = make_redirection (source, r_reading_until, redir, 0); | |||||
- redir_stack[need_here_doc++] = $$; | |||||
+ push_redir_stack ($$); | |||||
} | |||||
| REDIR_WORD LESS_LESS WORD | |||||
{ | |||||
source.filename = $1; | |||||
redir.filename = $3; | |||||
$$ = make_redirection (source, r_reading_until, redir, REDIR_VARASSIGN); | |||||
- redir_stack[need_here_doc++] = $$; | |||||
+ push_redir_stack ($$); | |||||
} | |||||
| LESS_LESS_MINUS WORD | |||||
{ | |||||
source.dest = 0; | |||||
redir.filename = $2; | |||||
$$ = make_redirection (source, r_deblank_reading_until, redir, 0); | |||||
- redir_stack[need_here_doc++] = $$; | |||||
+ push_redir_stack ($$); | |||||
} | |||||
| NUMBER LESS_LESS_MINUS WORD | |||||
{ | |||||
source.dest = $1; | |||||
redir.filename = $3; | |||||
$$ = make_redirection (source, r_deblank_reading_until, redir, 0); | |||||
- redir_stack[need_here_doc++] = $$; | |||||
+ push_redir_stack ($$); | |||||
} | |||||
| REDIR_WORD LESS_LESS_MINUS WORD | |||||
{ | |||||
source.filename = $1; | |||||
redir.filename = $3; | |||||
$$ = make_redirection (source, r_deblank_reading_until, redir, REDIR_VARASSIGN); | |||||
- redir_stack[need_here_doc++] = $$; | |||||
+ push_redir_stack ($$); | |||||
} | |||||
| LESS_LESS_LESS WORD | |||||
{ | |||||
@@ -4905,7 +4917,7 @@ got_token: | |||||
case CASE: | |||||
case SELECT: | |||||
case FOR: | |||||
- if (word_top < MAX_CASE_NEST) | |||||
+ if (word_top + 1 < MAX_CASE_NEST) | |||||
word_top++; | |||||
word_lineno[word_top] = line_number; | |||||
break; |
@ -1,148 +0,0 @@ | |||||
--- a/variables.c | |||||
+++ b/variables.c | |||||
@@ -279,7 +279,7 @@ static void push_temp_var __P((PTR_T)); | |||||
static void propagate_temp_var __P((PTR_T)); | |||||
static void dispose_temporary_env __P((sh_free_func_t *)); | |||||
-static inline char *mk_env_string __P((const char *, const char *)); | |||||
+static inline char *mk_env_string __P((const char *, const char *, int)); | |||||
static char **make_env_array_from_var_list __P((SHELL_VAR **)); | |||||
static char **make_var_export_array __P((VAR_CONTEXT *)); | |||||
static char **make_func_export_array __P((void)); | |||||
@@ -312,6 +312,14 @@ create_variable_tables () | |||||
#endif | |||||
} | |||||
+/* Prefix and suffix for environment variable names which contain | |||||
+ shell functions. */ | |||||
+#define FUNCDEF_PREFIX "BASH_FUNC_" | |||||
+#define FUNCDEF_PREFIX_LEN (strlen (FUNCDEF_PREFIX)) | |||||
+#define FUNCDEF_SUFFIX "()" | |||||
+#define FUNCDEF_SUFFIX_LEN (strlen (FUNCDEF_SUFFIX)) | |||||
+ | |||||
+ | |||||
/* Initialize the shell variables from the current environment. | |||||
If PRIVMODE is nonzero, don't import functions from ENV or | |||||
parse $SHELLOPTS. */ | |||||
@@ -349,22 +357,31 @@ initialize_shell_variables (env, privmod | |||||
/* If exported function, define it now. Don't import functions from | |||||
the environment in privileged mode. */ | |||||
- if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4)) | |||||
- { | |||||
- string_length = strlen (string); | |||||
- temp_string = (char *)xmalloc (3 + string_length + char_index); | |||||
+ if (privmode == 0 && read_but_dont_execute == 0 | |||||
+ && STREQN (FUNCDEF_PREFIX, name, FUNCDEF_PREFIX_LEN) | |||||
+ && STREQ (name + char_index - FUNCDEF_SUFFIX_LEN, FUNCDEF_SUFFIX) | |||||
+ && STREQN ("() {", string, 4)) | |||||
+ { | |||||
+ size_t name_length | |||||
+ = char_index - (FUNCDEF_PREFIX_LEN + FUNCDEF_SUFFIX_LEN); | |||||
+ char *temp_name = name + FUNCDEF_PREFIX_LEN; | |||||
+ /* Temporarily remove the suffix. */ | |||||
+ temp_name[name_length] = '\0'; | |||||
- strcpy (temp_string, name); | |||||
- temp_string[char_index] = ' '; | |||||
- strcpy (temp_string + char_index + 1, string); | |||||
+ string_length = strlen (string); | |||||
+ temp_string = (char *)xmalloc (name_length + 1 + string_length + 1); | |||||
+ memcpy (temp_string, temp_name, name_length); | |||||
+ temp_string[name_length] = ' '; | |||||
+ memcpy (temp_string + name_length + 1, string, string_length + 1); | |||||
/* Don't import function names that are invalid identifiers from the | |||||
environment, though we still allow them to be defined as shell | |||||
variables. */ | |||||
- if (legal_identifier (name)) | |||||
- parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD); | |||||
+ if (legal_identifier (temp_name)) | |||||
+ parse_and_execute (temp_string, temp_name, | |||||
+ SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD); | |||||
- if (temp_var = find_function (name)) | |||||
+ if (temp_var = find_function (temp_name)) | |||||
{ | |||||
VSETATTR (temp_var, (att_exported|att_imported)); | |||||
array_needs_making = 1; | |||||
@@ -379,6 +396,9 @@ initialize_shell_variables (env, privmod | |||||
last_command_exit_value = 1; | |||||
report_error (_("error importing function definition for `%s'"), name); | |||||
} | |||||
+ | |||||
+ /* Restore the original suffix. */ | |||||
+ temp_name[name_length] = FUNCDEF_SUFFIX[0]; | |||||
} | |||||
#if defined (ARRAY_VARS) | |||||
# if ARRAY_EXPORT | |||||
@@ -2954,7 +2974,7 @@ assign_in_env (word, flags) | |||||
var->context = variable_context; /* XXX */ | |||||
INVALIDATE_EXPORTSTR (var); | |||||
- var->exportstr = mk_env_string (name, value); | |||||
+ var->exportstr = mk_env_string (name, value, 0); | |||||
array_needs_making = 1; | |||||
@@ -3851,22 +3871,43 @@ merge_temporary_env () | |||||
/* */ | |||||
/* **************************************************************** */ | |||||
+/* Returns the string NAME=VALUE if !FUNCTIONP or if VALUE == NULL (in | |||||
+ which case it is treated as empty). Otherwise, decorate NAME with | |||||
+ FUNCDEF_PREFIX and FUNCDEF_SUFFIX, and return a string of the form | |||||
+ FUNCDEF_PREFIX NAME FUNCDEF_SUFFIX = VALUE (without spaces). */ | |||||
static inline char * | |||||
-mk_env_string (name, value) | |||||
+mk_env_string (name, value, functionp) | |||||
const char *name, *value; | |||||
+ int functionp; | |||||
{ | |||||
- int name_len, value_len; | |||||
- char *p; | |||||
+ size_t name_len, value_len; | |||||
+ char *p, *q; | |||||
name_len = strlen (name); | |||||
value_len = STRLEN (value); | |||||
- p = (char *)xmalloc (2 + name_len + value_len); | |||||
- strcpy (p, name); | |||||
- p[name_len] = '='; | |||||
+ if (functionp && value != NULL) | |||||
+ { | |||||
+ p = (char *)xmalloc (FUNCDEF_PREFIX_LEN + name_len + FUNCDEF_SUFFIX_LEN | |||||
+ + 1 + value_len + 1); | |||||
+ q = p; | |||||
+ memcpy (q, FUNCDEF_PREFIX, FUNCDEF_PREFIX_LEN); | |||||
+ q += FUNCDEF_PREFIX_LEN; | |||||
+ memcpy (q, name, name_len); | |||||
+ q += name_len; | |||||
+ memcpy (q, FUNCDEF_SUFFIX, FUNCDEF_SUFFIX_LEN); | |||||
+ q += FUNCDEF_SUFFIX_LEN; | |||||
+ } | |||||
+ else | |||||
+ { | |||||
+ p = (char *)xmalloc (name_len + 1 + value_len + 1); | |||||
+ memcpy (p, name, name_len); | |||||
+ q = p + name_len; | |||||
+ } | |||||
+ q[0] = '='; | |||||
if (value && *value) | |||||
- strcpy (p + name_len + 1, value); | |||||
+ memcpy (q + 1, value, value_len + 1); | |||||
else | |||||
- p[name_len + 1] = '\0'; | |||||
+ q[1] = '\0'; | |||||
return (p); | |||||
} | |||||
@@ -3952,7 +3993,7 @@ make_env_array_from_var_list (vars) | |||||
/* Gee, I'd like to get away with not using savestring() if we're | |||||
using the cached exportstr... */ | |||||
list[list_index] = USE_EXPORTSTR ? savestring (value) | |||||
- : mk_env_string (var->name, value); | |||||
+ : mk_env_string (var->name, value, function_p (var)); | |||||
if (USE_EXPORTSTR == 0) | |||||
SAVE_EXPORTSTR (var, list[list_index]); |