diff -u bash-4.2/debian/changelog bash-4.2/debian/changelog --- bash-4.2/debian/changelog +++ bash-4.2/debian/changelog @@ -1,3 +1,23 @@ +bash (4.2-2ubuntu2.6) precise-security; urgency=medium + + * SECURITY UPDATE: incorrect function definition parsing with + here-document delimited by end-of-file + - debian/patches/CVE-2014-6277.diff: properly handle closing delimiter + in bash/copy_cmd.c, bash/make_cmd.c. + - CVE-2014-6277 + * SECURITY UPDATE: incorrect function definition parsing via nested + command substitutions + - debian/patches/CVE-2014-6278.diff: properly handle certain parsing + attempts in bash/builtins/evalstring.c, bash/parse.y, bash/shell.h. + - CVE-2014-6278 + * Updated patches with official upstream versions: + - debian/patches/CVE-2014-6271.diff + - debian/patches/CVE-2014-7169.diff + - debian/patches/variables-affix.diff + - debian/patches/CVE-2014-718x.diff + + -- Marc Deslauriers Tue, 07 Oct 2014 11:05:06 -0400 + bash (4.2-2ubuntu2.5) precise-security; urgency=medium * SECURITY UPDATE: out-of-bounds memory access diff -u bash-4.2/debian/patches/variables-affix.diff bash-4.2/debian/patches/variables-affix.diff --- bash-4.2/debian/patches/variables-affix.diff +++ bash-4.2/debian/patches/variables-affix.diff @@ -1,12 +1,37 @@ -Description: use prefixes and suffixes for function exports -Author: Florian Weimer -Origin: vendor, http://www.openwall.com/lists/oss-security/2014/09/25/32 + BASH PATCH REPORT + ================= -Index: bash-4.2/bash/variables.c +Bash-Release: 4.2 +Patch-ID: bash42-050 + +Bug-Reported-by: Florian Weimer +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. + +Index: bash-4.2.temp/bash/variables.c =================================================================== ---- bash-4.2.orig/bash/variables.c 2014-09-25 14:46:19.596401815 -0400 -+++ bash-4.2/bash/variables.c 2014-09-25 14:46:39.736402354 -0400 -@@ -268,7 +268,7 @@ +--- bash-4.2.temp.orig/bash/variables.c 2014-10-07 11:02:24.162804496 -0400 ++++ bash-4.2.temp/bash/variables.c 2014-10-07 11:02:38.142804279 -0400 +@@ -79,6 +79,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. */ +@@ -268,7 +273,7 @@ static void propagate_temp_var __P((PTR_T)); static void dispose_temporary_env __P((sh_free_func_t *)); @@ -15,72 +40,58 @@ 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)); -@@ -301,6 +301,14 @@ - #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. */ -@@ -338,27 +346,39 @@ +@@ -338,27 +343,41 @@ /* 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); ++ 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); -+ 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'; ++ temp_string = (char *)xmalloc (namelen + string_length + 2); - 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); ++ 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. */ - 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 (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 (temp_name)) ++ if (temp_var = find_function (tname)) { VSETATTR (temp_var, (att_exported|att_imported)); array_needs_making = 1; } else - report_error (_("error importing function definition for `%s'"), name); +- report_error (_("error importing function definition for `%s'"), name); ++ report_error (_("error importing function definition for `%s'"), tname); + -+ /* Restore the original suffix. */ -+ temp_name[name_length] = FUNCDEF_SUFFIX[0]; ++ /* Restore original suffix */ ++ tname[namelen] = BASHFUNC_SUFFIX[0]; } #if defined (ARRAY_VARS) # if 0 -@@ -2537,7 +2557,7 @@ +@@ -2537,7 +2556,7 @@ var->context = variable_context; /* XXX */ INVALIDATE_EXPORTSTR (var); @@ -89,48 +100,46 @@ array_needs_making = 1; -@@ -3388,22 +3408,43 @@ - /* */ +@@ -3389,21 +3408,42 @@ /* **************************************************************** */ -+/* 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) ++mk_env_string (name, value, isfunc) const char *name, *value; -+ int functionp; ++ int isfunc; { - int name_len, value_len; - char *p; + size_t name_len, value_len; -+ char *p, *q; ++ 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) ++ ++ /* If we are exporting a shell function, construct the encoded function ++ name. */ ++ if (isfunc && value) + { -+ p = (char *)xmalloc (FUNCDEF_PREFIX_LEN + name_len + FUNCDEF_SUFFIX_LEN -+ + 1 + value_len + 1); ++ p = (char *)xmalloc (BASHFUNC_PREFLEN + name_len + BASHFUNC_SUFFLEN + value_len + 2); + q = p; -+ memcpy (q, FUNCDEF_PREFIX, FUNCDEF_PREFIX_LEN); -+ q += FUNCDEF_PREFIX_LEN; ++ memcpy (q, BASHFUNC_PREFIX, BASHFUNC_PREFLEN); ++ q += BASHFUNC_PREFLEN; + memcpy (q, name, name_len); + q += name_len; -+ memcpy (q, FUNCDEF_SUFFIX, FUNCDEF_SUFFIX_LEN); -+ q += FUNCDEF_SUFFIX_LEN; ++ memcpy (q, BASHFUNC_SUFFIX, BASHFUNC_SUFFLEN); ++ q += BASHFUNC_SUFFLEN; + } + else + { -+ p = (char *)xmalloc (name_len + 1 + value_len + 1); ++ 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); @@ -138,15 +147,16 @@ else - p[name_len + 1] = '\0'; + q[1] = '\0'; ++ return (p); } -@@ -3489,7 +3530,7 @@ +@@ -3489,7 +3529,7 @@ /* 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)); ++ : mk_env_string (var->name, value, function_p (var)); if (USE_EXPORTSTR == 0) SAVE_EXPORTSTR (var, list[list_index]); diff -u bash-4.2/debian/patches/CVE-2014-718x.diff bash-4.2/debian/patches/CVE-2014-718x.diff --- bash-4.2/debian/patches/CVE-2014-718x.diff +++ bash-4.2/debian/patches/CVE-2014-718x.diff @@ -1,40 +1,59 @@ -Description: fix out-of-bounds array accesses in parser - Thanks to Florian Weimer from Red Hat and Todd Sabin -Origin: vendor, http://www.openwall.com/lists/oss-security/2014/09/25/32 + BASH PATCH REPORT + ================= -Index: bash-4.2/bash/parse.y +Bash-Release: 4.2 +Patch-ID: bash42-051 + +Bug-Reported-by: Florian Weimer +Bug-Reference-ID: +Bug-Reference-URL: + +Bug-Description: + +There are two local buffer overflows in parse.y that can cause the shell +to dump core when given many here-documents attached to a single command +or many nested loops. + +Index: bash-4.2.temp/bash/parse.y =================================================================== ---- bash-4.2.orig/bash/parse.y 2014-09-25 14:45:36.852400670 -0400 -+++ bash-4.2/bash/parse.y 2014-09-25 14:46:03.300401379 -0400 -@@ -264,9 +264,21 @@ +--- bash-4.2.temp.orig/bash/parse.y 2014-10-07 11:02:50.000000000 -0400 ++++ bash-4.2.temp/bash/parse.y 2014-10-07 11:03:11.870803757 -0400 +@@ -167,6 +167,9 @@ + + static int reserved_word_acceptable __P((int)); + static int yylex __P((void)); ++ ++static void push_heredoc __P((REDIRECT *)); ++static char *mk_alexpansion __P((char *)); + static int alias_expand_token __P((char *)); + static int time_command_acceptable __P((void)); + static int special_case_tokens __P((char *)); +@@ -264,7 +267,9 @@ /* 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; ++#define HEREDOC_MAX 16 ++ ++static REDIRECT *redir_stack[HEREDOC_MAX]; 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; -@@ -519,42 +531,42 @@ +@@ -306,7 +311,7 @@ + or `for WORD' begins. This is a nested command maximum, since the array + index is decremented after a case, select, or for command is parsed. */ + #define MAX_CASE_NEST 128 +-static int word_lineno[MAX_CASE_NEST]; ++static int word_lineno[MAX_CASE_NEST+1]; + static int word_top = -1; + + /* If non-zero, it is the token that we want read_token to return +@@ -519,42 +524,42 @@ source.dest = 0; redir.filename = $2; $$ = make_redirection (source, r_reading_until, redir, 0); - redir_stack[need_here_doc++] = $$; -+ push_redir_stack ($$); ++ push_heredoc ($$); } | NUMBER LESS_LESS WORD { @@ -42,7 +61,7 @@ redir.filename = $3; $$ = make_redirection (source, r_reading_until, redir, 0); - redir_stack[need_here_doc++] = $$; -+ push_redir_stack ($$); ++ push_heredoc ($$); } | REDIR_WORD LESS_LESS WORD { @@ -50,7 +69,7 @@ redir.filename = $3; $$ = make_redirection (source, r_reading_until, redir, REDIR_VARASSIGN); - redir_stack[need_here_doc++] = $$; -+ push_redir_stack ($$); ++ push_heredoc ($$); } | LESS_LESS_MINUS WORD { @@ -58,7 +77,7 @@ redir.filename = $2; $$ = make_redirection (source, r_deblank_reading_until, redir, 0); - redir_stack[need_here_doc++] = $$; -+ push_redir_stack ($$); ++ push_heredoc ($$); } | NUMBER LESS_LESS_MINUS WORD { @@ -66,7 +85,7 @@ redir.filename = $3; $$ = make_redirection (source, r_deblank_reading_until, redir, 0); - redir_stack[need_here_doc++] = $$; -+ push_redir_stack ($$); ++ push_heredoc ($$); } | REDIR_WORD LESS_LESS_MINUS WORD { @@ -77,13 +96,26 @@ -+ push_redir_stack ($$); ++ push_heredoc ($$); } | LESS_LESS_LESS WORD { -@@ -4757,7 +4769,7 @@ - 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; +@@ -2531,6 +2536,21 @@ + which allow ESAC to be the next one read. */ + static int esacs_needed_count; + ++static void ++push_heredoc (r) ++ REDIRECT *r; ++{ ++ if (need_here_doc >= HEREDOC_MAX) ++ { ++ last_command_exit_value = EX_BADUSAGE; ++ need_here_doc = 0; ++ report_syntax_error (_("maximum here-document count exceeded")); ++ reset_parser (); ++ exit_shell (last_command_exit_value); ++ } ++ redir_stack[need_here_doc++] = r; ++} ++ + void + gather_here_documents () + { diff -u bash-4.2/debian/patches/series.in bash-4.2/debian/patches/series.in --- bash-4.2/debian/patches/series.in +++ bash-4.2/debian/patches/series.in @@ -54,2 +54,4 @@ -CVE-2014-718x.diff variables-affix.diff +CVE-2014-718x.diff +CVE-2014-6277.diff +CVE-2014-6278.diff diff -u bash-4.2/debian/patches/CVE-2014-6271.diff bash-4.2/debian/patches/CVE-2014-6271.diff --- bash-4.2/debian/patches/CVE-2014-6271.diff +++ bash-4.2/debian/patches/CVE-2014-6271.diff @@ -1,10 +1,22 @@ -Description: fix incorrect function parsing -Author: Chet Ramey + BASH PATCH REPORT + ================= -Index: bash-4.2/bash/builtins/common.h +Bash-Release: 4.2 +Patch-ID: bash42-048 + +Bug-Reported-by: Stephane Chazelas +Bug-Reference-ID: +Bug-Reference-URL: + +Bug-Description: + +Under certain circumstances, bash will execute user code while processing the +environment for exported function definitions. + +Index: bash-4.2.temp/bash/builtins/common.h =================================================================== ---- bash-4.2.orig/bash/builtins/common.h 2010-05-30 18:31:51.000000000 -0400 -+++ bash-4.2/bash/builtins/common.h 2014-09-22 15:30:40.372413446 -0400 +--- bash-4.2.temp.orig/bash/builtins/common.h 2014-10-07 11:00:22.000000000 -0400 ++++ bash-4.2.temp/bash/builtins/common.h 2014-10-07 11:01:40.550805172 -0400 @@ -35,6 +35,8 @@ #define SEVAL_NOLONGJMP 0x040 @@ -14,10 +26,10 @@ #define CDESC_ALL 0x001 /* type -a */ #define CDESC_SHORTDESC 0x002 /* command -V */ #define CDESC_REUSABLE 0x004 /* command -v */ -Index: bash-4.2/bash/builtins/evalstring.c +Index: bash-4.2.temp/bash/builtins/evalstring.c =================================================================== ---- bash-4.2.orig/bash/builtins/evalstring.c 2010-11-23 08:22:15.000000000 -0500 -+++ bash-4.2/bash/builtins/evalstring.c 2014-09-22 15:30:40.372413446 -0400 +--- bash-4.2.temp.orig/bash/builtins/evalstring.c 2014-10-07 11:00:22.000000000 -0400 ++++ bash-4.2.temp/bash/builtins/evalstring.c 2014-10-07 11:01:40.550805172 -0400 @@ -261,6 +261,14 @@ { struct fd_bitmap *bitmap; @@ -43,10 +55,10 @@ } } else -Index: bash-4.2/bash/variables.c +Index: bash-4.2.temp/bash/variables.c =================================================================== ---- bash-4.2.orig/bash/variables.c 2014-09-22 15:29:30.188411567 -0400 -+++ bash-4.2/bash/variables.c 2014-09-22 15:30:40.372413446 -0400 +--- bash-4.2.temp.orig/bash/variables.c 2014-10-07 11:00:48.586805977 -0400 ++++ bash-4.2.temp/bash/variables.c 2014-10-07 11:01:40.554805172 -0400 @@ -347,12 +347,10 @@ temp_string[char_index] = ' '; strcpy (temp_string + char_index + 1, string); diff -u bash-4.2/debian/patches/CVE-2014-7169.diff bash-4.2/debian/patches/CVE-2014-7169.diff --- bash-4.2/debian/patches/CVE-2014-7169.diff +++ bash-4.2/debian/patches/CVE-2014-7169.diff @@ -1,11 +1,22 @@ -Description: fix incomplete CVE-2014-6271 update -Author: Chet Ramey -Origin: upstream, http://www.openwall.com/lists/oss-security/2014/09/25/10 + BASH PATCH REPORT + ================= -Index: bash-4.2/bash/parse.y +Bash-Release: 4.2 +Patch-ID: bash42-049 + +Bug-Reported-by: Tavis Ormandy +Bug-Reference-ID: +Bug-Reference-URL: http://twitter.com/taviso/statuses/514887394294652929 + +Bug-Description: + +Under certain circumstances, bash can incorrectly save a lookahead character and +return it on a subsequent call, even when reading a new line. + +Index: bash-4.2.temp/bash/parse.y =================================================================== ---- bash-4.2.orig/bash/parse.y 2014-09-25 02:09:45.791186206 -0400 -+++ bash-4.2/bash/parse.y 2014-09-25 02:09:45.791186206 -0400 +--- bash-4.2.temp.orig/bash/parse.y 2014-10-07 11:01:53.882804965 -0400 ++++ bash-4.2.temp/bash/parse.y 2014-10-07 11:02:08.066804745 -0400 @@ -2848,6 +2848,8 @@ FREE (word_desc_to_read); word_desc_to_read = (WORD_DESC *)NULL; only in patch2: unchanged: --- bash-4.2.orig/debian/patches/CVE-2014-6277.diff +++ bash-4.2/debian/patches/CVE-2014-6277.diff @@ -0,0 +1,42 @@ + BASH PATCH REPORT + ================= + +Bash-Release: 4.2 +Patch-ID: bash42-052 + +Bug-Reported-by: Michal Zalewski +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. + +Index: bash-4.2.temp/bash/copy_cmd.c +=================================================================== +--- bash-4.2.temp.orig/bash/copy_cmd.c 2009-09-11 16:28:02.000000000 -0400 ++++ bash-4.2.temp/bash/copy_cmd.c 2014-10-07 11:04:13.950802795 -0400 +@@ -126,7 +126,7 @@ + { + 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: +Index: bash-4.2.temp/bash/make_cmd.c +=================================================================== +--- bash-4.2.temp.orig/bash/make_cmd.c 2009-09-11 17:26:12.000000000 -0400 ++++ bash-4.2.temp/bash/make_cmd.c 2014-10-07 11:04:13.946802795 -0400 +@@ -689,6 +689,7 @@ + /* 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; only in patch2: unchanged: --- bash-4.2.orig/debian/patches/CVE-2014-6278.diff +++ bash-4.2/debian/patches/CVE-2014-6278.diff @@ -0,0 +1,108 @@ + BASH PATCH REPORT + ================= + +Bash-Release: 4.2 +Patch-ID: bash42-053 + +Bug-Reported-by: Michal Zalewski +Bug-Reference-ID: +Bug-Reference-URL: + +Bug-Description: + +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. + +Index: bash-4.2.temp/bash/builtins/evalstring.c +=================================================================== +--- bash-4.2.temp.orig/bash/builtins/evalstring.c 2014-10-07 11:04:23.614802645 -0400 ++++ bash-4.2.temp/bash/builtins/evalstring.c 2014-10-07 11:04:51.262802217 -0400 +@@ -261,12 +261,25 @@ + { + 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 @@ + discard_unwind_frame ("pe_dispose"); + + if (flags & SEVAL_ONECMD) +- break; ++ { ++ reset_parser (); ++ break; ++ } + } + } + else +Index: bash-4.2.temp/bash/parse.y +=================================================================== +--- bash-4.2.temp.orig/bash/parse.y 2014-10-07 11:04:23.650802645 -0400 ++++ bash-4.2.temp/bash/parse.y 2014-10-07 11:04:51.266802217 -0400 +@@ -2433,6 +2433,16 @@ + 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 +@@ -3888,8 +3898,8 @@ + reset_parser (); + /* reset_parser clears shell_input_line and associated variables */ + restore_input_line_state (&ls); +- 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 +Index: bash-4.2.temp/bash/shell.h +=================================================================== +--- bash-4.2.temp.orig/bash/shell.h 2014-10-07 11:04:23.158802652 -0400 ++++ bash-4.2.temp/bash/shell.h 2014-10-07 11:04:51.266802217 -0400 +@@ -177,6 +177,8 @@ + } sh_input_line_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 *)); +