Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Sat, 27 Sep 2014 21:39:19 -0400
From: Chet Ramey <chet.ramey@...e.edu>
To: Tavis Ormandy <taviso@...xchg8b.com>, Florian Weimer <fw@...eb.enyo.de>
CC: chet.ramey@...e.edu, Michal Zalewski <lcamtuf@...edump.cx>,
        Solar Designer <solar@...nwall.com>, oss-security@...ts.openwall.com,
        Eric Blake <eblake@...hat.com>
Subject: Re: CVE-2014-6271: remote code execution through bash

On 9/27/14, 2:17 PM, Chet Ramey wrote:
> On 9/27/14, 10:28 AM, Tavis Ormandy wrote:
> 
>> It does look bad, but are you sold on the prefix/suffix solution Chet?
>> That will at least mean these are not security issues.
> 
> Yes.  I have no problems worth mentioning with the exported function
> encoding approach.  I have attached patches implementing it that can
> be applied to bash versions from bash-2.05b to bash-4.3.  Please take
> a look, make sure they can be applied cleanly, and so on.
> 
> There is another discussion worth having before officially releasing
> these, which I will do later today.

OK, here are the more-or-less final versions of the patches for bash-2.05b
through bash-4.3.  I made two changes from earlier today: the function
export suffix is now `%%', which is not part of a the set of valid variable
name characters but avoids any potential problems with including
shell metacharacters in the name; and this version refuses to import shell
functions whose name contains a slash, for reasons I discussed earlier.

Please let me know if you have any issues with these.

Chet
-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
		 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRU    chet@...e.edu    http://cnswww.cns.cwru.edu/~chet/

*** ../bash-2.05b.09/variables.c	2014-09-25 10:18:20.000000000 -0400
--- variables.c	2014-09-27 21:03:53.000000000 -0400
***************
*** 70,73 ****
--- 70,78 ----
  #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) */
+ 
  /* Variables used here and defined in other files. */
  extern int posixly_correct;
***************
*** 204,208 ****
  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 *));
--- 209,213 ----
  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 *));
***************
*** 261,279 ****
        /* 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));
--- 266,295 ----
        /* 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));
***************
*** 281,285 ****
  	    }
  	  else
! 	    report_error ("error importing function definition for `%s'", name);
  	}
  #if defined (ARRAY_VARS)
--- 297,304 ----
  	    }
  	  else
! 	    report_error ("error importing function definition for `%s'", tname);
! 
! 	  /* Restore original suffix */
! 	  tname[namelen] = BASHFUNC_SUFFIX[0];
  	}
  #if defined (ARRAY_VARS)
***************
*** 1924,1928 ****
  
    INVALIDATE_EXPORTSTR (var);
!   var->exportstr = mk_env_string (name, value);
  
    array_needs_making = 1;
--- 1943,1947 ----
  
    INVALIDATE_EXPORTSTR (var);
!   var->exportstr = mk_env_string (name, value, 0);
  
    array_needs_making = 1;
***************
*** 2682,2700 ****
  
  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);
  }
--- 2701,2740 ----
  
  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);
  }
***************
*** 2771,2775 ****
  	     using the cached exportstr... */
  	  list[list_index] = USE_EXPORTSTR ? savestring (value)
! 					   : mk_env_string (var->name, value);
  
  	  if (USE_EXPORTSTR == 0)
--- 2811,2815 ----
  	     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-3.0.18/variables.c	2014-09-16 21:57:03.000000000 -0400
--- variables.c	2014-09-27 21:03:18.000000000 -0400
***************
*** 71,74 ****
--- 71,79 ----
  #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) */
+ 
  /* Variables used here and defined in other files. */
  extern int posixly_correct;
***************
*** 228,232 ****
  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 *));
--- 233,237 ----
  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 *));
***************
*** 290,308 ****
        /* 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));
--- 295,324 ----
        /* 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));
***************
*** 310,314 ****
  	    }
  	  else
! 	    report_error (_("error importing function definition for `%s'"), name);
  	}
  #if defined (ARRAY_VARS)
--- 326,333 ----
  	    }
  	  else
! 	    report_error (_("error importing function definition for `%s'"), tname);
! 
! 	  /* Restore original suffix */
! 	  tname[namelen] = BASHFUNC_SUFFIX[0];
  	}
  #if defined (ARRAY_VARS)
***************
*** 2113,2117 ****
  
    INVALIDATE_EXPORTSTR (var);
!   var->exportstr = mk_env_string (name, value);
  
    array_needs_making = 1;
--- 2132,2136 ----
  
    INVALIDATE_EXPORTSTR (var);
!   var->exportstr = mk_env_string (name, value, 0);
  
    array_needs_making = 1;
***************
*** 2896,2914 ****
  
  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);
  }
--- 2915,2954 ----
  
  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);
  }
***************
*** 2985,2989 ****
  	     using the cached exportstr... */
  	  list[list_index] = USE_EXPORTSTR ? savestring (value)
! 					   : mk_env_string (var->name, value);
  
  	  if (USE_EXPORTSTR == 0)
--- 3025,3029 ----
  	     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-3.1.19/variables.c	2014-09-16 22:00:02.000000000 -0400
--- variables.c	2014-09-27 21:02:50.000000000 -0400
***************
*** 75,78 ****
--- 75,83 ----
  #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;
  
***************
*** 240,244 ****
  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 *));
--- 245,249 ----
  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 *));
***************
*** 302,320 ****
        /* 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));
--- 307,336 ----
        /* 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));
***************
*** 322,326 ****
  	    }
  	  else
! 	    report_error (_("error importing function definition for `%s'"), name);
  	}
  #if defined (ARRAY_VARS)
--- 338,345 ----
  	    }
  	  else
! 	    report_error (_("error importing function definition for `%s'"), tname);
! 
! 	  /* Restore original suffix */
! 	  tname[namelen] = BASHFUNC_SUFFIX[0];
  	}
  #if defined (ARRAY_VARS)
***************
*** 2215,2219 ****
  
    INVALIDATE_EXPORTSTR (var);
!   var->exportstr = mk_env_string (name, value);
  
    array_needs_making = 1;
--- 2234,2238 ----
  
    INVALIDATE_EXPORTSTR (var);
!   var->exportstr = mk_env_string (name, value, 0);
  
    array_needs_making = 1;
***************
*** 3003,3021 ****
  
  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);
  }
--- 3022,3061 ----
  
  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);
  }
***************
*** 3092,3096 ****
  	     using the cached exportstr... */
  	  list[list_index] = USE_EXPORTSTR ? savestring (value)
! 					   : mk_env_string (var->name, value);
  
  	  if (USE_EXPORTSTR == 0)
--- 3132,3136 ----
  	     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-3.2.53/variables.c	2014-09-16 19:10:39.000000000 -0400
--- variables.c	2014-09-27 21:02:08.000000000 -0400
***************
*** 75,78 ****
--- 75,83 ----
  #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;
  
***************
*** 242,246 ****
  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 *));
--- 247,251 ----
  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 *));
***************
*** 310,328 ****
        /* 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));
--- 315,344 ----
        /* 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));
***************
*** 330,334 ****
  	    }
  	  else
! 	    report_error (_("error importing function definition for `%s'"), name);
  	}
  #if defined (ARRAY_VARS)
--- 346,353 ----
  	    }
  	  else
! 	    report_error (_("error importing function definition for `%s'"), tname);
! 
! 	  /* Restore original suffix */
! 	  tname[namelen] = BASHFUNC_SUFFIX[0];
  	}
  #if defined (ARRAY_VARS)
***************
*** 2208,2212 ****
  
    INVALIDATE_EXPORTSTR (var);
!   var->exportstr = mk_env_string (name, value);
  
    array_needs_making = 1;
--- 2227,2231 ----
  
    INVALIDATE_EXPORTSTR (var);
!   var->exportstr = mk_env_string (name, value, 0);
  
    array_needs_making = 1;
***************
*** 2999,3017 ****
  
  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);
  }
--- 3018,3057 ----
  
  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);
  }
***************
*** 3088,3092 ****
  	     using the cached exportstr... */
  	  list[list_index] = USE_EXPORTSTR ? savestring (value)
! 					   : mk_env_string (var->name, value);
  
  	  if (USE_EXPORTSTR == 0)
--- 3128,3132 ----
  	     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.0.40/variables.c	2014-09-16 19:20:48.000000000 -0400
--- variables.c	2014-09-27 21:01:42.000000000 -0400
***************
*** 78,81 ****
--- 78,86 ----
  #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;
  
***************
*** 265,269 ****
  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 *));
--- 270,274 ----
  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 *));
***************
*** 335,353 ****
        /* 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));
--- 340,369 ----
        /* 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));
***************
*** 355,359 ****
  	    }
  	  else
! 	    report_error (_("error importing function definition for `%s'"), name);
  	}
  #if defined (ARRAY_VARS)
--- 371,378 ----
  	    }
  	  else
! 	    report_error (_("error importing function definition for `%s'"), tname);
! 
! 	  /* Restore original suffix */
! 	  tname[namelen] = BASHFUNC_SUFFIX[0];
  	}
  #if defined (ARRAY_VARS)
***************
*** 2506,2510 ****
  
    INVALIDATE_EXPORTSTR (var);
!   var->exportstr = mk_env_string (name, value);
  
    array_needs_making = 1;
--- 2525,2529 ----
  
    INVALIDATE_EXPORTSTR (var);
!   var->exportstr = mk_env_string (name, value, 0);
  
    array_needs_making = 1;
***************
*** 3325,3343 ****
  
  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);
  }
--- 3344,3383 ----
  
  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);
  }
***************
*** 3420,3424 ****
  	     using the cached exportstr... */
  	  list[list_index] = USE_EXPORTSTR ? savestring (value)
! 					   : mk_env_string (var->name, value);
  
  	  if (USE_EXPORTSTR == 0)
--- 3460,3464 ----
  	     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.1.13/variables.c	2014-09-16 19:27:38.000000000 -0400
--- variables.c	2014-09-27 20:57:46.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)
***************
*** 2520,2524 ****
  
    INVALIDATE_EXPORTSTR (var);
!   var->exportstr = mk_env_string (name, value);
  
    array_needs_making = 1;
--- 2539,2543 ----
  
    INVALIDATE_EXPORTSTR (var);
!   var->exportstr = mk_env_string (name, value, 0);
  
    array_needs_making = 1;
***************
*** 3339,3357 ****
  
  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);
  }
--- 3358,3397 ----
  
  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);
  }
***************
*** 3439,3443 ****
  	     using the cached exportstr... */
  	  list[list_index] = USE_EXPORTSTR ? savestring (value)
! 					   : mk_env_string (var->name, value);
  
  	  if (USE_EXPORTSTR == 0)
--- 3479,3483 ----
  	     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.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.3.26/variables.c	2014-09-25 23:02:18.000000000 -0400
--- variables.c	2014-09-27 20:52:04.000000000 -0400
***************
*** 84,87 ****
--- 84,92 ----
  #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;
  
***************
*** 280,284 ****
  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 *));
--- 285,289 ----
  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 *));
***************
*** 350,369 ****
        /* 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, 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 (temp_var = find_function (name))
  	    {
  	      VSETATTR (temp_var, (att_exported|att_imported));
--- 355,385 ----
        /* 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, though we still allow them to be defined as shell
  	     variables. */
! 	  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));
***************
*** 378,383 ****
  		}
  	      last_command_exit_value = 1;
! 	      report_error (_("error importing function definition for `%s'"), name);
  	    }
  	}
  #if defined (ARRAY_VARS)
--- 394,402 ----
  		}
  	      last_command_exit_value = 1;
! 	      report_error (_("error importing function definition for `%s'"), tname);
  	    }
+ 
+ 	  /* Restore original suffix */
+ 	  tname[namelen] = BASHFUNC_SUFFIX[0];
  	}
  #if defined (ARRAY_VARS)
***************
*** 2955,2959 ****
  
    INVALIDATE_EXPORTSTR (var);
!   var->exportstr = mk_env_string (name, value);
  
    array_needs_making = 1;
--- 2974,2978 ----
  
    INVALIDATE_EXPORTSTR (var);
!   var->exportstr = mk_env_string (name, value, 0);
  
    array_needs_making = 1;
***************
*** 3853,3871 ****
  
  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);
  }
--- 3872,3911 ----
  
  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);
  }
***************
*** 3953,3957 ****
  	     using the cached exportstr... */
  	  list[list_index] = USE_EXPORTSTR ? savestring (value)
! 					   : mk_env_string (var->name, value);
  
  	  if (USE_EXPORTSTR == 0)
--- 3993,3997 ----
  	     using the cached exportstr... */
  	  list[list_index] = USE_EXPORTSTR ? savestring (value)
! 					   : mk_env_string (var->name, value, function_p (var));
  
  	  if (USE_EXPORTSTR == 0)

Powered by blists - more mailing lists

Your e-mail address:

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Powered by Openwall GNU/*/Linux - Powered by OpenVZ