From 80df778bb8f868423dfe5fc9847238eee8d0a764 Mon Sep 17 00:00:00 2001 From: Michal Zalewski Date: Fri, 10 Oct 2014 11:16:06 +0100 Subject: bugfix: bash executing code following func def This is an upstream bugfix (with slight alterations): Patch-ID: bash42-053 A combination of nested command substitutions and function importing from the environment can cause bash to execute code appearing in the environment variable value following the function definition. Change-Id: I660e59c76d0d50de52d48a0d399fe1dfef3bded8 --- builtins/evalstring.c | 28 ++++++++++++++++++++++------ parse.y | 14 ++++++++++++-- shell.h | 2 ++ y.tab.c | 13 +++++++++++-- 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/builtins/evalstring.c b/builtins/evalstring.c index 61f57fc..c2bce74 100644 --- a/builtins/evalstring.c +++ b/builtins/evalstring.c @@ -261,12 +261,25 @@ parse_and_execute (string, from_file, flags) { struct fd_bitmap *bitmap; - if ((flags & SEVAL_FUNCDEF) && command->type != cm_function_def) + if (flags & SEVAL_FUNCDEF) { - internal_warning ("%s: ignoring function definition attempt", from_file); - should_jump_to_top_level = 0; - last_result = last_command_exit_value = EX_BADUSAGE; - break; + char *x; + + /* If the command parses to something other than a straight + function definition, or if we have not consumed the entire + string, or if the parser has transformed the function + name (as parsing will if it begins or ends with shell + whitespace, for example), reject the attempt */ + if (command->type != cm_function_def || + ((x = parser_remaining_input ()) && *x) || + (STREQ (from_file, command->value.Function_def->name->word) == 0)) + { + internal_warning (_("%s: ignoring function definition attempt"), from_file); + should_jump_to_top_level = 0; + last_result = last_command_exit_value = EX_BADUSAGE; + reset_parser (); + break; + } } bitmap = new_fd_bitmap (FD_BITMAP_SIZE); @@ -331,7 +344,10 @@ parse_and_execute (string, from_file, flags) discard_unwind_frame ("pe_dispose"); if (flags & SEVAL_ONECMD) - break; + { + reset_parser (); + break; + } } } else diff --git a/parse.y b/parse.y index b3c17bc..b4ef178 100644 --- a/parse.y +++ b/parse.y @@ -2433,6 +2433,16 @@ shell_ungetc (c) eol_ungetc_lookahead = c; } +char * +parser_remaining_input () +{ + if (shell_input_line == 0) + return 0; + if (shell_input_line_index < 0 || shell_input_line_index >= shell_input_line_len) + return '\0'; /* XXX */ + return (shell_input_line + shell_input_line_index); +} + #ifdef INCLUDE_UNUSED /* Back the input pointer up by one, effectively `ungetting' a character. */ static void @@ -3883,8 +3893,8 @@ xparse_dolparen (base, string, indp, flags) restore_parser_state (&ps); reset_parser (); - if (interactive) - token_to_read = 0; + + token_to_read = 0; /* Need to find how many characters parse_and_execute consumed, update *indp, if flags != 0, copy the portion of the string parsed into RET diff --git a/shell.h b/shell.h index 92685e1..a643d80 100644 --- a/shell.h +++ b/shell.h @@ -167,5 +167,7 @@ typedef struct _sh_parser_state_t { } sh_parser_state_t; /* Let's try declaring these here. */ +extern char *parser_remaining_input __P((void)); + extern sh_parser_state_t *save_parser_state __P((sh_parser_state_t *)); extern void restore_parser_state __P((sh_parser_state_t *)); diff --git a/y.tab.c b/y.tab.c index 677960f..f72f81e 100644 --- a/y.tab.c +++ b/y.tab.c @@ -4746,6 +4746,16 @@ shell_ungetc (c) eol_ungetc_lookahead = c; } +char * +parser_remaining_input () +{ + if (shell_input_line == 0) + return 0; + if (shell_input_line_index < 0 || shell_input_line_index >= shell_input_line_len) + return '\0'; /* XXX */ + return (shell_input_line + shell_input_line_index); +} + #ifdef INCLUDE_UNUSED /* Back the input pointer up by one, effectively `ungetting' a character. */ static void @@ -6196,8 +6206,7 @@ xparse_dolparen (base, string, indp, flags) restore_parser_state (&ps); reset_parser (); - if (interactive) - token_to_read = 0; + token_to_read = 0; /* Need to find how many characters parse_and_execute consumed, update *indp, if flags != 0, copy the portion of the string parsed into RET -- cgit v1.1