19701904 problem in UTILITY/BASH
authorStefan Teleman <stefan.teleman@oracle.com>
Tue, 21 Oct 2014 19:21:36 -0700
changeset 2165 d1946b7b1894
parent 2164 b580bc10e31a
child 2166 7f088f5637d1
19701904 problem in UTILITY/BASH
components/bash/patches/bash42-048.patch
components/bash/patches/bash42-049.patch
components/bash/patches/bash42-050.patch
components/bash/patches/bash42-051.patch
components/bash/patches/bash42-052.patch
components/bash/patches/bash42-053.patch
components/bash/patches/funcdef-import-4.2-CVE-2014-6271.patch
components/bash/patches/parse.y-CVE-2014-7169.patch
components/bash/patches/parser-oob-4.2.patch
components/bash/patches/variables-affix-4.2.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/bash/patches/bash42-048.patch	Tue Oct 21 19:21:36 2014 -0700
@@ -0,0 +1,104 @@
+			     BASH PATCH REPORT
+			     =================
+
+Bash-Release:	4.2
+Patch-ID:	bash42-048
+
+Bug-Reported-by:	Stephane Chazelas <[email protected]>
+Bug-Reference-ID:
+Bug-Reference-URL:
+
+Bug-Description:
+
+Under certain circumstances, bash will execute user code while processing the
+environment for exported function definitions.
+
+Patch (apply with `patch -p0'):
+
+*** ../bash-4.2.47/builtins/common.h	2010-05-30 18:31:51.000000000 -0400
+--- builtins/common.h	2014-09-16 19:35:45.000000000 -0400
+***************
+*** 36,39 ****
+--- 36,41 ----
+  
+  /* Flags for describe_command, shared between type.def and command.def */
++ #define SEVAL_FUNCDEF	0x080		/* only allow function definitions */
++ #define SEVAL_ONECMD	0x100		/* only allow a single command */
+  #define CDESC_ALL		0x001	/* type -a */
+  #define CDESC_SHORTDESC		0x002	/* command -V */
+*** ../bash-4.2.47/builtins/evalstring.c	2010-11-23 08:22:15.000000000 -0500
+--- builtins/evalstring.c	2014-09-16 19:35:45.000000000 -0400
+***************
+*** 262,265 ****
+--- 262,273 ----
+  	      struct fd_bitmap *bitmap;
+  
++ 	      if ((flags & SEVAL_FUNCDEF) && command->type != cm_function_def)
++ 		{
++ 		  internal_warning ("%s: ignoring function definition attempt", from_file);
++ 		  should_jump_to_top_level = 0;
++ 		  last_result = last_command_exit_value = EX_BADUSAGE;
++ 		  break;
++ 		}
++ 
+  	      bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
+  	      begin_unwind_frame ("pe_dispose");
+***************
+*** 322,325 ****
+--- 330,336 ----
+  	      dispose_fd_bitmap (bitmap);
+  	      discard_unwind_frame ("pe_dispose");
++ 
++ 	      if (flags & SEVAL_ONECMD)
++ 		break;
+  	    }
+  	}
+*** ../bash-4.2.47/variables.c	2011-03-01 16:15:20.000000000 -0500
+--- variables.c	2014-09-16 19:35:45.000000000 -0400
+***************
+*** 348,357 ****
+  	  strcpy (temp_string + char_index + 1, string);
+  
+! 	  parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
+! 
+! 	  /* Ancient backwards compatibility.  Old versions of bash exported
+! 	     functions like name()=() {...} */
+! 	  if (name[char_index - 1] == ')' && name[char_index - 2] == '(')
+! 	    name[char_index - 2] = '\0';
+  
+  	  if (temp_var = find_function (name))
+--- 348,355 ----
+  	  strcpy (temp_string + char_index + 1, string);
+  
+! 	  /* 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 (temp_var = find_function (name))
+***************
+*** 362,369 ****
+  	  else
+  	    report_error (_("error importing function definition for `%s'"), name);
+- 
+- 	  /* ( */
+- 	  if (name[char_index - 1] == ')' && name[char_index - 2] == '\0')
+- 	    name[char_index - 2] = '(';		/* ) */
+  	}
+  #if defined (ARRAY_VARS)
+--- 360,363 ----
+*** ../bash-4.2-patched/patchlevel.h	Sat Jun 12 20:14:48 2010
+--- patchlevel.h	Thu Feb 24 21:41:34 2011
+***************
+*** 26,30 ****
+     looks for to find the patch level (for the sccs version string). */
+  
+! #define PATCHLEVEL 47
+  
+  #endif /* _PATCHLEVEL_H_ */
+--- 26,30 ----
+     looks for to find the patch level (for the sccs version string). */
+  
+! #define PATCHLEVEL 48
+  
+  #endif /* _PATCHLEVEL_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/bash/patches/bash42-049.patch	Tue Oct 21 19:21:36 2014 -0700
@@ -0,0 +1,43 @@
+			     BASH PATCH REPORT
+			     =================
+
+Bash-Release:	4.2
+Patch-ID:	bash42-049
+
+Bug-Reported-by:	Tavis Ormandy <[email protected]>
+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.
+
+Patch (apply with `patch -p0'):
+
+*** ../bash-4.2.48/parse.y	2012-12-31 11:52:57.000000000 -0500
+--- parse.y	2014-09-25 16:12:19.000000000 -0400
+***************
+*** 2851,2854 ****
+--- 2851,2856 ----
+    word_desc_to_read = (WORD_DESC *)NULL;
+  
++   eol_ungetc_lookahead = 0;
++ 
+    current_token = '\n';		/* XXX */
+    last_read_token = '\n';
+*** ../bash-4.2-patched/patchlevel.h	Sat Jun 12 20:14:48 2010
+--- patchlevel.h	Thu Feb 24 21:41:34 2011
+***************
+*** 26,30 ****
+     looks for to find the patch level (for the sccs version string). */
+  
+! #define PATCHLEVEL 48
+  
+  #endif /* _PATCHLEVEL_H_ */
+--- 26,30 ----
+     looks for to find the patch level (for the sccs version string). */
+  
+! #define PATCHLEVEL 49
+  
+  #endif /* _PATCHLEVEL_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/bash/patches/bash42-050.patch	Tue Oct 21 19:21:36 2014 -0700
@@ -0,0 +1,217 @@
+			     BASH PATCH REPORT
+			     =================
+
+Bash-Release:	4.2
+Patch-ID:	bash42-050
+
+Bug-Reported-by:	Florian Weimer <[email protected]>
+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'):
+
+*** ../bash-4.2.49/variables.c	2014-09-16 19:35:45.000000000 -0400
+--- variables.c	2014-09-27 20:54:00.000000000 -0400
+***************
+*** 80,83 ****
+--- 80,88 ----
+  #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;
+  
+***************
+*** 269,273 ****
+  static void dispose_temporary_env __P((sh_free_func_t *));     
+  
+! static inline char *mk_env_string __P((const char *, const char *));
+  static char **make_env_array_from_var_list __P((SHELL_VAR **));
+  static char **make_var_export_array __P((VAR_CONTEXT *));
+--- 274,278 ----
+  static void dispose_temporary_env __P((sh_free_func_t *));     
+  
+! 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 *));
+***************
+*** 339,357 ****
+        /* 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);
+  
+! 	  strcpy (temp_string, name);
+! 	  temp_string[char_index] = ' ';
+! 	  strcpy (temp_string + char_index + 1, string);
+  
+  	  /* 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 (temp_var = find_function (name))
+  	    {
+  	      VSETATTR (temp_var, (att_exported|att_imported));
+--- 344,373 ----
+        /* 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 (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 (namelen + string_length + 2);
+  
+! 	  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 (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 (tname))
+  	    {
+  	      VSETATTR (temp_var, (att_exported|att_imported));
+***************
+*** 359,363 ****
+  	    }
+  	  else
+! 	    report_error (_("error importing function definition for `%s'"), name);
+  	}
+  #if defined (ARRAY_VARS)
+--- 375,382 ----
+  	    }
+  	  else
+! 	    report_error (_("error importing function definition for `%s'"), tname);
+! 
+! 	  /* Restore original suffix */
+! 	  tname[namelen] = BASHFUNC_SUFFIX[0];
+  	}
+  #if defined (ARRAY_VARS)
+***************
+*** 2538,2542 ****
+  
+    INVALIDATE_EXPORTSTR (var);
+!   var->exportstr = mk_env_string (name, value);
+  
+    array_needs_making = 1;
+--- 2557,2561 ----
+  
+    INVALIDATE_EXPORTSTR (var);
+!   var->exportstr = mk_env_string (name, value, 0);
+  
+    array_needs_making = 1;
+***************
+*** 3390,3408 ****
+  
+  static inline char *
+! mk_env_string (name, value)
+       const char *name, *value;
+  {
+!   int name_len, value_len;
+!   char	*p;
+  
+    name_len = strlen (name);
+    value_len = STRLEN (value);
+!   p = (char *)xmalloc (2 + name_len + value_len);
+!   strcpy (p, name);
+!   p[name_len] = '=';
+    if (value && *value)
+!     strcpy (p + name_len + 1, value);
+    else
+!     p[name_len + 1] = '\0';
+    return (p);
+  }
+--- 3409,3448 ----
+  
+  static inline char *
+! mk_env_string (name, value, isfunc)
+       const char *name, *value;
++      int isfunc;
+  {
+!   size_t name_len, value_len;
+!   char	*p, *q;
+  
+    name_len = strlen (name);
+    value_len = STRLEN (value);
+! 
+!   /* 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)
+!     memcpy (q + 1, value, value_len + 1);
+    else
+!     q[1] = '\0';
+! 
+    return (p);
+  }
+***************
+*** 3490,3494 ****
+  	     using the cached exportstr... */
+  	  list[list_index] = USE_EXPORTSTR ? savestring (value)
+! 					   : mk_env_string (var->name, value);
+  
+  	  if (USE_EXPORTSTR == 0)
+--- 3530,3534 ----
+  	     using the cached exportstr... */
+  	  list[list_index] = USE_EXPORTSTR ? savestring (value)
+! 					   : mk_env_string (var->name, value, function_p (var));
+  
+  	  if (USE_EXPORTSTR == 0)
+*** ../bash-4.2-patched/patchlevel.h	Sat Jun 12 20:14:48 2010
+--- patchlevel.h	Thu Feb 24 21:41:34 2011
+***************
+*** 26,30 ****
+     looks for to find the patch level (for the sccs version string). */
+  
+! #define PATCHLEVEL 49
+  
+  #endif /* _PATCHLEVEL_H_ */
+--- 26,30 ----
+     looks for to find the patch level (for the sccs version string). */
+  
+! #define PATCHLEVEL 50
+  
+  #endif /* _PATCHLEVEL_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/bash/patches/bash42-051.patch	Tue Oct 21 19:21:36 2014 -0700
@@ -0,0 +1,173 @@
+			     BASH PATCH REPORT
+			     =================
+
+Bash-Release:	4.2
+Patch-ID:	bash42-051
+
+Bug-Reported-by:	Florian Weimer <[email protected]>
+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.
+
+Patch (apply with `patch -p0'):
+
+*** ../bash-4.2.50/parse.y	2014-09-27 12:18:53.000000000 -0400
+--- parse.y	2014-09-30 19:24:19.000000000 -0400
+***************
+*** 168,171 ****
+--- 168,174 ----
+  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));
+***************
+*** 265,269 ****
+  /* 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];
+  int need_here_doc;
+  
+--- 268,274 ----
+  /* Variables to manage the task of reading here documents, because we need to
+     defer the reading until after a complete command has been collected. */
+! #define HEREDOC_MAX 16
+! 
+! static REDIRECT *redir_stack[HEREDOC_MAX];
+  int need_here_doc;
+  
+***************
+*** 307,311 ****
+     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_top = -1;
+  
+--- 312,316 ----
+     index is decremented after a case, select, or for command is parsed. */
+  #define MAX_CASE_NEST	128
+! static int word_lineno[MAX_CASE_NEST+1];
+  static int word_top = -1;
+  
+***************
+*** 520,524 ****
+  			  redir.filename = $2;
+  			  $$ = make_redirection (source, r_reading_until, redir, 0);
+! 			  redir_stack[need_here_doc++] = $$;
+  			}
+  	|	NUMBER LESS_LESS WORD
+--- 525,529 ----
+  			  redir.filename = $2;
+  			  $$ = make_redirection (source, r_reading_until, redir, 0);
+! 			  push_heredoc ($$);
+  			}
+  	|	NUMBER LESS_LESS WORD
+***************
+*** 527,531 ****
+  			  redir.filename = $3;
+  			  $$ = make_redirection (source, r_reading_until, redir, 0);
+! 			  redir_stack[need_here_doc++] = $$;
+  			}
+  	|	REDIR_WORD LESS_LESS WORD
+--- 532,536 ----
+  			  redir.filename = $3;
+  			  $$ = make_redirection (source, r_reading_until, redir, 0);
+! 			  push_heredoc ($$);
+  			}
+  	|	REDIR_WORD LESS_LESS WORD
+***************
+*** 534,538 ****
+  			  redir.filename = $3;
+  			  $$ = make_redirection (source, r_reading_until, redir, REDIR_VARASSIGN);
+! 			  redir_stack[need_here_doc++] = $$;
+  			}
+  	|	LESS_LESS_MINUS WORD
+--- 539,543 ----
+  			  redir.filename = $3;
+  			  $$ = make_redirection (source, r_reading_until, redir, REDIR_VARASSIGN);
+! 			  push_heredoc ($$);
+  			}
+  	|	LESS_LESS_MINUS WORD
+***************
+*** 541,545 ****
+  			  redir.filename = $2;
+  			  $$ = make_redirection (source, r_deblank_reading_until, redir, 0);
+! 			  redir_stack[need_here_doc++] = $$;
+  			}
+  	|	NUMBER LESS_LESS_MINUS WORD
+--- 546,550 ----
+  			  redir.filename = $2;
+  			  $$ = make_redirection (source, r_deblank_reading_until, redir, 0);
+! 			  push_heredoc ($$);
+  			}
+  	|	NUMBER LESS_LESS_MINUS WORD
+***************
+*** 548,552 ****
+  			  redir.filename = $3;
+  			  $$ = make_redirection (source, r_deblank_reading_until, redir, 0);
+! 			  redir_stack[need_here_doc++] = $$;
+  			}
+  	|	REDIR_WORD  LESS_LESS_MINUS WORD
+--- 553,557 ----
+  			  redir.filename = $3;
+  			  $$ = make_redirection (source, r_deblank_reading_until, redir, 0);
+! 			  push_heredoc ($$);
+  			}
+  	|	REDIR_WORD  LESS_LESS_MINUS WORD
+***************
+*** 555,559 ****
+  			  redir.filename = $3;
+  			  $$ = make_redirection (source, r_deblank_reading_until, redir, REDIR_VARASSIGN);
+! 			  redir_stack[need_here_doc++] = $$;
+  			}
+  	|	LESS_LESS_LESS WORD
+--- 560,564 ----
+  			  redir.filename = $3;
+  			  $$ = make_redirection (source, r_deblank_reading_until, redir, REDIR_VARASSIGN);
+! 			  push_heredoc ($$);
+  			}
+  	|	LESS_LESS_LESS WORD
+***************
+*** 2534,2537 ****
+--- 2539,2557 ----
+  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 ()
+*** ../bash-4.2-patched/patchlevel.h	Sat Jun 12 20:14:48 2010
+--- patchlevel.h	Thu Feb 24 21:41:34 2011
+***************
+*** 26,30 ****
+     looks for to find the patch level (for the sccs version string). */
+  
+! #define PATCHLEVEL 50
+  
+  #endif /* _PATCHLEVEL_H_ */
+--- 26,30 ----
+     looks for to find the patch level (for the sccs version string). */
+  
+! #define PATCHLEVEL 51
+  
+  #endif /* _PATCHLEVEL_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/bash/patches/bash42-052.patch	Tue Oct 21 19:21:36 2014 -0700
@@ -0,0 +1,59 @@
+			     BASH PATCH REPORT
+			     =================
+
+Bash-Release:	4.2
+Patch-ID:	bash42-052
+
+Bug-Reported-by:	Michal Zalewski <[email protected]>
+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'):
+
+*** ../bash-4.2.51/make_cmd.c	2009-09-11 17:26:12.000000000 -0400
+--- make_cmd.c	2014-10-02 11:26:58.000000000 -0400
+***************
+*** 690,693 ****
+--- 690,694 ----
+    temp->redirector = source;
+    temp->redirectee = dest_and_filename;
++   temp->here_doc_eof = 0;
+    temp->instruction = instruction;
+    temp->flags = 0;
+*** ../bash-4.2.51/copy_cmd.c	2009-09-11 16:28:02.000000000 -0400
+--- copy_cmd.c	2014-10-02 11:26:58.000000000 -0400
+***************
+*** 127,131 ****
+      case r_reading_until:
+      case r_deblank_reading_until:
+!       new_redirect->here_doc_eof = savestring (redirect->here_doc_eof);
+        /*FALLTHROUGH*/
+      case r_reading_string:
+--- 127,131 ----
+      case r_reading_until:
+      case r_deblank_reading_until:
+!       new_redirect->here_doc_eof = redirect->here_doc_eof ? savestring (redirect->here_doc_eof) : 0;
+        /*FALLTHROUGH*/
+      case r_reading_string:
+*** ../bash-4.2-patched/patchlevel.h	Sat Jun 12 20:14:48 2010
+--- patchlevel.h	Thu Feb 24 21:41:34 2011
+***************
+*** 26,30 ****
+     looks for to find the patch level (for the sccs version string). */
+  
+! #define PATCHLEVEL 51
+  
+  #endif /* _PATCHLEVEL_H_ */
+--- 26,30 ----
+     looks for to find the patch level (for the sccs version string). */
+  
+! #define PATCHLEVEL 52
+  
+  #endif /* _PATCHLEVEL_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/bash/patches/bash42-053.patch	Tue Oct 21 19:21:36 2014 -0700
@@ -0,0 +1,132 @@
+			     BASH PATCH REPORT
+			     =================
+
+Bash-Release:	4.2
+Patch-ID:	bash42-053
+
+Bug-Reported-by:	Michal Zalewski <[email protected]>
+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.
+
+Patch (apply with `patch -p0'):
+
+*** ../bash-4.2.52/builtins/evalstring.c	2014-09-16 19:35:45.000000000 -0400
+--- builtins/evalstring.c	2014-10-04 15:00:26.000000000 -0400
+***************
+*** 262,271 ****
+  	      struct fd_bitmap *bitmap;
+  
+! 	      if ((flags & SEVAL_FUNCDEF) && command->type != cm_function_def)
+  		{
+! 		  internal_warning ("%s: ignoring function definition attempt", from_file);
+! 		  should_jump_to_top_level = 0;
+! 		  last_result = last_command_exit_value = EX_BADUSAGE;
+! 		  break;
+  		}
+  
+--- 262,284 ----
+  	      struct fd_bitmap *bitmap;
+  
+! 	      if (flags & SEVAL_FUNCDEF)
+  		{
+! 		  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;
+! 		    }
+  		}
+  
+***************
+*** 332,336 ****
+  
+  	      if (flags & SEVAL_ONECMD)
+! 		break;
+  	    }
+  	}
+--- 345,352 ----
+  
+  	      if (flags & SEVAL_ONECMD)
+! 		{
+! 		  reset_parser ();
+! 		  break;
+! 		}
+  	    }
+  	}
+*** ../bash-4.2.52/parse.y	2014-09-30 19:24:19.000000000 -0400
+--- parse.y	2014-10-04 15:00:26.000000000 -0400
+***************
+*** 2436,2439 ****
+--- 2436,2449 ----
+  }
+  
++ 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. */
+***************
+*** 3891,3896 ****
+    /* reset_parser clears shell_input_line and associated variables */
+    restore_input_line_state (&ls);
+!   if (interactive)
+!     token_to_read = 0;
+  
+    /* Need to find how many characters parse_and_execute consumed, update
+--- 3901,3906 ----
+    /* reset_parser clears shell_input_line and associated variables */
+    restore_input_line_state (&ls);
+! 
+!   token_to_read = 0;
+  
+    /* Need to find how many characters parse_and_execute consumed, update
+*** ../bash-4.2.52/shell.h	2011-11-21 18:03:32.000000000 -0500
+--- shell.h	2014-10-04 15:00:26.000000000 -0400
+***************
+*** 178,181 ****
+--- 178,183 ----
+  
+  /* 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 *));
+*** ../bash-4.2-patched/patchlevel.h	Sat Jun 12 20:14:48 2010
+--- patchlevel.h	Thu Feb 24 21:41:34 2011
+***************
+*** 26,30 ****
+     looks for to find the patch level (for the sccs version string). */
+  
+! #define PATCHLEVEL 52
+  
+  #endif /* _PATCHLEVEL_H_ */
+--- 26,30 ----
+     looks for to find the patch level (for the sccs version string). */
+  
+! #define PATCHLEVEL 53
+  
+  #endif /* _PATCHLEVEL_H_ */
--- a/components/bash/patches/funcdef-import-4.2-CVE-2014-6271.patch	Tue Oct 21 12:20:30 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-# Patch is from the bash project.
-# It is currently embargo'ed (as of 2014-02-23).
-# It will become an official bash patch once the embargo is lifted.
-*** ../bash-4.2.47/builtins/common.h	2010-05-30 18:31:51.000000000 -0400
---- builtins/common.h	2014-09-16 19:35:45.000000000 -0400
-***************
-*** 36,39 ****
---- 36,41 ----
-  
-  /* Flags for describe_command, shared between type.def and command.def */
-+ #define SEVAL_FUNCDEF	0x080		/* only allow function definitions */
-+ #define SEVAL_ONECMD	0x100		/* only allow a single command */
-  #define CDESC_ALL		0x001	/* type -a */
-  #define CDESC_SHORTDESC		0x002	/* command -V */
-*** ../bash-4.2.47/builtins/evalstring.c	2010-11-23 08:22:15.000000000 -0500
---- builtins/evalstring.c	2014-09-16 19:35:45.000000000 -0400
-***************
-*** 262,265 ****
---- 262,273 ----
-  	      struct fd_bitmap *bitmap;
-  
-+ 	      if ((flags & SEVAL_FUNCDEF) && command->type != cm_function_def)
-+ 		{
-+ 		  internal_warning ("%s: ignoring function definition attempt", from_file);
-+ 		  should_jump_to_top_level = 0;
-+ 		  last_result = last_command_exit_value = EX_BADUSAGE;
-+ 		  break;
-+ 		}
-+ 
-  	      bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
-  	      begin_unwind_frame ("pe_dispose");
-***************
-*** 322,325 ****
---- 330,336 ----
-  	      dispose_fd_bitmap (bitmap);
-  	      discard_unwind_frame ("pe_dispose");
-+ 
-+ 	      if (flags & SEVAL_ONECMD)
-+ 		break;
-  	    }
-  	}
-*** ../bash-4.2.47/variables.c	2011-03-01 16:15:20.000000000 -0500
---- variables.c	2014-09-16 19:35:45.000000000 -0400
-***************
-*** 348,357 ****
-  	  strcpy (temp_string + char_index + 1, string);
-  
-! 	  parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
-! 
-! 	  /* Ancient backwards compatibility.  Old versions of bash exported
-! 	     functions like name()=() {...} */
-! 	  if (name[char_index - 1] == ')' && name[char_index - 2] == '(')
-! 	    name[char_index - 2] = '\0';
-  
-  	  if (temp_var = find_function (name))
---- 348,355 ----
-  	  strcpy (temp_string + char_index + 1, string);
-  
-! 	  /* 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 (temp_var = find_function (name))
-***************
-*** 362,369 ****
-  	  else
-  	    report_error (_("error importing function definition for `%s'"), name);
-- 
-- 	  /* ( */
-- 	  if (name[char_index - 1] == ')' && name[char_index - 2] == '\0')
-- 	    name[char_index - 2] = '(';		/* ) */
-  	}
-  #if defined (ARRAY_VARS)
---- 360,363 ----
-
--- a/components/bash/patches/parse.y-CVE-2014-7169.patch	Tue Oct 21 12:20:30 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-# Patch is from Chet Ramey (Bash Project Lead);
-# http://www.openwall.com/lists/oss-security/2014/09/25/10
-# This will become an official bash patch.
-*** ../bash-20140912/parse.y	2014-08-26 15:09:42.000000000 -0400
---- parse.y	2014-09-24 22:47:28.000000000 -0400
-***************
-*** 2959,2962 ****
---- 2959,2964 ----
-    word_desc_to_read = (WORD_DESC *)NULL;
-  
-+   eol_ungetc_lookahead = 0;
-+ 
-    current_token = '\n';		/* XXX */
-    last_read_token = '\n';
-
--- a/components/bash/patches/parser-oob-4.2.patch	Tue Oct 21 12:20:30 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-# Patch Origin: http://www.openwall.com/lists/oss-security/2014/09/26/2
-# Patch is from Red Hat Security.
-# Assigned CVE-2014-7186 and CVE-2014-7187
-# CVSS Score: 4.6
---- ../bash-4.2-orig/parse.y	2014-09-25 13:07:59.218209276 +0200
-+++ parse.y	2014-09-25 15:26:52.813159810 +0200
-@@ -264,9 +264,21 @@
- 
- /* 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;
-@@ -519,42 +531,42 @@
- 			  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
- 			{
-@@ -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;
-
-
-
--- a/components/bash/patches/variables-affix-4.2.patch	Tue Oct 21 12:20:30 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-# Patch Origin: http://www.openwall.com/lists/oss-security/2014/09/25/32
-# Patch is from Red Hat Security.
-# CVE-2014-7619
-# CVSS Score:10.0
-# This is an update to the previously released patchset for the same
-# vulnerability. The previous patch did NOT cover all possible attack
-# vectors.
---- ../bash-4.2-orig/variables.c	2014-09-25 13:07:59.313209541 +0200
-+++ variables.c	2014-09-25 13:15:29.869420719 +0200
-@@ -268,7 +268,7 @@
- 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));
-@@ -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 @@
- 
-       /* 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. */
--	  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;
- 	    }
- 	  else
- 	    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 0
-@@ -2537,7 +2557,7 @@
-   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;
- 
-@@ -3388,22 +3408,43 @@
- /*								    */
- /* **************************************************************** */
- 
-+/* 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);
- }
- 
-@@ -3489,7 +3530,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));
- 
- 	  if (USE_EXPORTSTR == 0)
- 	    SAVE_EXPORTSTR (var, list[list_index]);
-
-