Fixes CVE-2014-6271.
Signed-off-by: Marcel Denia <naoir@gmx.net>
#
-# Copyright (C) 2007-2012 OpenWrt.org
+# Copyright (C) 2007-2014 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
PKG_NAME:=bash
PKG_VERSION:=4.2
-PKG_RELEASE:=3
+PKG_RELEASE:=4
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=@GNU/bash
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-029
+
+Bug-Reported-by: "Michael Kalisz" <michael@kalisz.homelinux.net>
+Bug-Reference-ID: <50241.78.69.11.112.1298585641.squirrel@kalisz.homelinux.net>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2011-02/msg00274.html
+
+Bug-Description:
+
+Bash-4.2 tries to leave completed directory names as the user typed them,
+without expanding them to a full pathname. One effect of this is that
+shell variables used in pathnames being completed (e.g., $HOME) are left
+unchanged, but the `$' is quoted by readline because it is a special
+character to the shell.
+
+This patch introduces two things:
+
+1. A new shell option, `direxpand', which, if set, attempts to emulate the
+ bash-4.1 behavior of expanding words to full pathnames during
+ completion;
+2. A set of heuristics that reduce the number of times special characters
+ such as `$' are quoted when the directory name is not expanded.
+
+Patch (apply with `patch -p0'):
+
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 28
++#define PATCHLEVEL 29
+
+ #endif /* _PATCHLEVEL_H_ */
+--- a/bashline.c
++++ b/bashline.c
+@@ -121,6 +121,9 @@ static int bash_directory_completion_hoo
+ static int filename_completion_ignore __P((char **));
+ static int bash_push_line __P((void));
+
++static rl_icppfunc_t *save_directory_hook __P((void));
++static void reset_directory_hook __P((rl_icppfunc_t *));
++
+ static void cleanup_expansion_error __P((void));
+ static void maybe_make_readline_line __P((char *));
+ static void set_up_new_line __P((char *));
+@@ -243,10 +246,17 @@ int force_fignore = 1;
+ /* Perform spelling correction on directory names during word completion */
+ int dircomplete_spelling = 0;
+
++/* Expand directory names during word/filename completion. */
++int dircomplete_expand = 0;
++int dircomplete_expand_relpath = 0;
++
+ static char *bash_completer_word_break_characters = " \t\n\"'@><=;|&(:";
+ static char *bash_nohostname_word_break_characters = " \t\n\"'><=;|&(:";
+ /* )) */
+
++static const char *default_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:{~"; /*}*/
++static char *custom_filename_quote_characters = 0;
++
+ static rl_hook_func_t *old_rl_startup_hook = (rl_hook_func_t *)NULL;
+
+ static int dot_in_path = 0;
+@@ -501,7 +511,7 @@ initialize_readline ()
+
+ /* Tell the completer that we might want to follow symbolic links or
+ do other expansion on directory names. */
+- rl_directory_rewrite_hook = bash_directory_completion_hook;
++ set_directory_hook ();
+
+ rl_filename_rewrite_hook = bash_filename_rewrite_hook;
+
+@@ -529,7 +539,7 @@ initialize_readline ()
+ enable_hostname_completion (perform_hostname_completion);
+
+ /* characters that need to be quoted when appearing in filenames. */
+- rl_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:{~"; /*}*/
++ rl_filename_quote_characters = default_filename_quote_characters;
+
+ rl_filename_quoting_function = bash_quote_filename;
+ rl_filename_dequoting_function = bash_dequote_filename;
+@@ -564,8 +574,10 @@ bashline_reset ()
+ tilde_initialize ();
+ rl_attempted_completion_function = attempt_shell_completion;
+ rl_completion_entry_function = NULL;
+- rl_directory_rewrite_hook = bash_directory_completion_hook;
+ rl_ignore_some_completions_function = filename_completion_ignore;
++ rl_filename_quote_characters = default_filename_quote_characters;
++
++ set_directory_hook ();
+ }
+
+ /* Contains the line to push into readline. */
+@@ -1279,6 +1291,9 @@ attempt_shell_completion (text, start, e
+ matches = (char **)NULL;
+ rl_ignore_some_completions_function = filename_completion_ignore;
+
++ rl_filename_quote_characters = default_filename_quote_characters;
++ set_directory_hook ();
++
+ /* Determine if this could be a command word. It is if it appears at
+ the start of the line (ignoring preceding whitespace), or if it
+ appears after a character that separates commands. It cannot be a
+@@ -1591,6 +1606,12 @@ command_word_completion_function (hint_t
+ }
+ else
+ {
++ if (dircomplete_expand && dot_or_dotdot (filename_hint))
++ {
++ dircomplete_expand = 0;
++ set_directory_hook ();
++ dircomplete_expand = 1;
++ }
+ mapping_over = 4;
+ goto inner;
+ }
+@@ -1791,6 +1812,9 @@ globword:
+
+ inner:
+ val = rl_filename_completion_function (filename_hint, istate);
++ if (mapping_over == 4 && dircomplete_expand)
++ set_directory_hook ();
++
+ istate = 1;
+
+ if (val == 0)
+@@ -2693,6 +2717,52 @@ bash_filename_rewrite_hook (fname, fnlen
+ return conv;
+ }
+
++/* Functions to save and restore the appropriate directory hook */
++/* This is not static so the shopt code can call it */
++void
++set_directory_hook ()
++{
++ if (dircomplete_expand)
++ {
++ rl_directory_completion_hook = bash_directory_completion_hook;
++ rl_directory_rewrite_hook = (rl_icppfunc_t *)0;
++ }
++ else
++ {
++ rl_directory_rewrite_hook = bash_directory_completion_hook;
++ rl_directory_completion_hook = (rl_icppfunc_t *)0;
++ }
++}
++
++static rl_icppfunc_t *
++save_directory_hook ()
++{
++ rl_icppfunc_t *ret;
++
++ if (dircomplete_expand)
++ {
++ ret = rl_directory_completion_hook;
++ rl_directory_completion_hook = (rl_icppfunc_t *)NULL;
++ }
++ else
++ {
++ ret = rl_directory_rewrite_hook;
++ rl_directory_rewrite_hook = (rl_icppfunc_t *)NULL;
++ }
++
++ return ret;
++}
++
++static void
++restore_directory_hook (hookf)
++ rl_icppfunc_t *hookf;
++{
++ if (dircomplete_expand)
++ rl_directory_completion_hook = hookf;
++ else
++ rl_directory_rewrite_hook = hookf;
++}
++
+ /* Handle symbolic link references and other directory name
+ expansions while hacking completion. This should return 1 if it modifies
+ the DIRNAME argument, 0 otherwise. It should make sure not to modify
+@@ -2702,20 +2772,31 @@ bash_directory_completion_hook (dirname)
+ char **dirname;
+ {
+ char *local_dirname, *new_dirname, *t;
+- int return_value, should_expand_dirname;
++ int return_value, should_expand_dirname, nextch, closer;
+ WORD_LIST *wl;
+ struct stat sb;
+
+- return_value = should_expand_dirname = 0;
++ return_value = should_expand_dirname = nextch = closer = 0;
+ local_dirname = *dirname;
+
+- if (mbschr (local_dirname, '$'))
+- should_expand_dirname = 1;
++ if (t = mbschr (local_dirname, '$'))
++ {
++ should_expand_dirname = '$';
++ nextch = t[1];
++ /* Deliberately does not handle the deprecated $[...] arithmetic
++ expansion syntax */
++ if (nextch == '(')
++ closer = ')';
++ else if (nextch == '{')
++ closer = '}';
++ else
++ nextch = 0;
++ }
+ else
+ {
+ t = mbschr (local_dirname, '`');
+ if (t && unclosed_pair (local_dirname, strlen (local_dirname), "`") == 0)
+- should_expand_dirname = 1;
++ should_expand_dirname = '`';
+ }
+
+ #if defined (HAVE_LSTAT)
+@@ -2739,6 +2820,23 @@ bash_directory_completion_hook (dirname)
+ free (new_dirname);
+ dispose_words (wl);
+ local_dirname = *dirname;
++ /* XXX - change rl_filename_quote_characters here based on
++ should_expand_dirname/nextch/closer. This is the only place
++ custom_filename_quote_characters is modified. */
++ if (rl_filename_quote_characters && *rl_filename_quote_characters)
++ {
++ int i, j, c;
++ i = strlen (default_filename_quote_characters);
++ custom_filename_quote_characters = xrealloc (custom_filename_quote_characters, i+1);
++ for (i = j = 0; c = default_filename_quote_characters[i]; i++)
++ {
++ if (c == should_expand_dirname || c == nextch || c == closer)
++ continue;
++ custom_filename_quote_characters[j++] = c;
++ }
++ custom_filename_quote_characters[j] = '\0';
++ rl_filename_quote_characters = custom_filename_quote_characters;
++ }
+ }
+ else
+ {
+@@ -2758,11 +2856,31 @@ bash_directory_completion_hook (dirname)
+ local_dirname = *dirname = new_dirname;
+ }
+
++ /* no_symbolic_links == 0 -> use (default) logical view of the file system.
++ local_dirname[0] == '.' && local_dirname[1] == '/' means files in the
++ current directory (./).
++ local_dirname[0] == '.' && local_dirname[1] == 0 means relative pathnames
++ in the current directory (e.g., lib/sh).
++ XXX - should we do spelling correction on these? */
++
++ /* This is test as it was in bash-4.2: skip relative pathnames in current
++ directory. Change test to
++ (local_dirname[0] != '.' || (local_dirname[1] && local_dirname[1] != '/'))
++ if we want to skip paths beginning with ./ also. */
+ if (no_symbolic_links == 0 && (local_dirname[0] != '.' || local_dirname[1]))
+ {
+ char *temp1, *temp2;
+ int len1, len2;
+
++ /* If we have a relative path
++ (local_dirname[0] != '/' && local_dirname[0] != '.')
++ that is canonical after appending it to the current directory, then
++ temp1 = temp2+'/'
++ That is,
++ strcmp (temp1, temp2) == 0
++ after adding a slash to temp2 below. It should be safe to not
++ change those.
++ */
+ t = get_working_directory ("symlink-hook");
+ temp1 = make_absolute (local_dirname, t);
+ free (t);
+@@ -2797,7 +2915,15 @@ bash_directory_completion_hook (dirname)
+ temp2[len2 + 1] = '\0';
+ }
+ }
+- return_value |= STREQ (local_dirname, temp2) == 0;
++
++ /* dircomplete_expand_relpath == 0 means we want to leave relative
++ pathnames that are unchanged by canonicalization alone.
++ *local_dirname != '/' && *local_dirname != '.' == relative pathname
++ (consistent with general.c:absolute_pathname())
++ temp1 == temp2 (after appending a slash to temp2) means the pathname
++ is not changed by canonicalization as described above. */
++ if (dircomplete_expand_relpath || ((local_dirname[0] != '/' && local_dirname[0] != '.') && STREQ (temp1, temp2) == 0))
++ return_value |= STREQ (local_dirname, temp2) == 0;
+ free (local_dirname);
+ *dirname = temp2;
+ free (temp1);
+@@ -3002,12 +3128,13 @@ bash_complete_filename_internal (what_to
+
+ orig_func = rl_completion_entry_function;
+ orig_attempt_func = rl_attempted_completion_function;
+- orig_dir_func = rl_directory_rewrite_hook;
+ orig_ignore_func = rl_ignore_some_completions_function;
+ orig_rl_completer_word_break_characters = rl_completer_word_break_characters;
++
++ orig_dir_func = save_directory_hook ();
++
+ rl_completion_entry_function = rl_filename_completion_function;
+ rl_attempted_completion_function = (rl_completion_func_t *)NULL;
+- rl_directory_rewrite_hook = (rl_icppfunc_t *)NULL;
+ rl_ignore_some_completions_function = filename_completion_ignore;
+ rl_completer_word_break_characters = " \t\n\"\'";
+
+@@ -3015,10 +3142,11 @@ bash_complete_filename_internal (what_to
+
+ rl_completion_entry_function = orig_func;
+ rl_attempted_completion_function = orig_attempt_func;
+- rl_directory_rewrite_hook = orig_dir_func;
+ rl_ignore_some_completions_function = orig_ignore_func;
+ rl_completer_word_break_characters = orig_rl_completer_word_break_characters;
+
++ restore_directory_hook (orig_dir_func);
++
+ return r;
+ }
+
+--- a/bashline.h
++++ b/bashline.h
+@@ -33,10 +33,15 @@ extern void bashline_reset __P((void));
+ extern void bashline_reinitialize __P((void));
+ extern int bash_re_edit __P((char *));
+
++extern void bashline_set_event_hook __P((void));
++extern void bashline_reset_event_hook __P((void));
++
+ extern int bind_keyseq_to_unix_command __P((char *));
+
+ extern char **bash_default_completion __P((const char *, int, int, int, int));
+
++void set_directory_hook __P((void));
++
+ /* Used by programmable completion code. */
+ extern char *command_word_completion_function __P((const char *, int));
+ extern char *bash_groupname_completion_function __P((const char *, int));
+--- a/builtins/shopt.def
++++ b/builtins/shopt.def
+@@ -61,6 +61,10 @@ $END
+ #include "common.h"
+ #include "bashgetopt.h"
+
++#if defined (READLINE)
++# include "../bashline.h"
++#endif
++
+ #if defined (HISTORY)
+ # include "../bashhist.h"
+ #endif
+@@ -94,7 +98,7 @@ extern int extended_glob;
+ extern int hist_verify, history_reediting, perform_hostname_completion;
+ extern int no_empty_command_completion;
+ extern int force_fignore;
+-extern int dircomplete_spelling;
++extern int dircomplete_spelling, dircomplete_expand;
+
+ extern int enable_hostname_completion __P((int));
+ #endif
+@@ -121,6 +125,10 @@ static int set_compatibility_level __P((
+ static int set_restricted_shell __P((char *, int));
+ #endif
+
++#if defined (READLINE)
++static int shopt_set_complete_direxpand __P((char *, int));
++#endif
++
+ static int shopt_login_shell;
+ static int shopt_compat31;
+ static int shopt_compat32;
+@@ -150,6 +158,7 @@ static struct {
+ { "compat40", &shopt_compat40, set_compatibility_level },
+ { "compat41", &shopt_compat41, set_compatibility_level },
+ #if defined (READLINE)
++ { "direxpand", &dircomplete_expand, shopt_set_complete_direxpand },
+ { "dirspell", &dircomplete_spelling, (shopt_set_func_t *)NULL },
+ #endif
+ { "dotglob", &glob_dot_filenames, (shopt_set_func_t *)NULL },
+@@ -535,6 +544,17 @@ set_compatibility_level (option_name, mo
+ return 0;
+ }
+
++#if defined (READLINE)
++static int
++shopt_set_complete_direxpand (option_name, mode)
++ char *option_name;
++ int mode;
++{
++ set_directory_hook ();
++ return 0;
++}
++#endif
++
+ #if defined (RESTRICTED_SHELL)
+ /* Don't allow the value of restricted_shell to be modified. */
+
+--- a/doc/bash.1
++++ b/doc/bash.1
+@@ -8948,6 +8948,16 @@ parameter expansion as a special charact
+ quoted. This is the behavior of posix mode through version 4.1.
+ The default bash behavior remains as in previous versions.
+ .TP 8
++.B direxpand
++If set,
++.B bash
++replaces directory names with the results of word expansion when performing
++filename completion. This changes the contents of the readline editing
++buffer.
++If not set,
++.B bash
++attempts to preserve what the user typed.
++.TP 8
+ .B dirspell
+ If set,
+ .B bash
+--- a/doc/bashref.texi
++++ b/doc/bashref.texi
+@@ -4535,6 +4535,13 @@ parameter expansion as a special charact
+ quoted. This is the behavior of @sc{posix} mode through version 4.1.
+ The default Bash behavior remains as in previous versions.
+
++@item direxpand
++If set, Bash
++replaces directory names with the results of word expansion when performing
++filename completion. This changes the contents of the readline editing
++buffer.
++If not set, Bash attempts to preserve what the user typed.
++
+ @item dirspell
+ If set, Bash
+ attempts spelling correction on directory names during word completion
+--- a/tests/shopt.right
++++ b/tests/shopt.right
+@@ -12,6 +12,7 @@ shopt -u compat31
+ shopt -u compat32
+ shopt -u compat40
+ shopt -u compat41
++shopt -u direxpand
+ shopt -u dirspell
+ shopt -u dotglob
+ shopt -u execfail
+@@ -68,6 +69,7 @@ shopt -u compat31
+ shopt -u compat32
+ shopt -u compat40
+ shopt -u compat41
++shopt -u direxpand
+ shopt -u dirspell
+ shopt -u dotglob
+ shopt -u execfail
+@@ -101,6 +103,7 @@ compat31 off
+ compat32 off
+ compat40 off
+ compat41 off
++direxpand off
+ dirspell off
+ dotglob off
+ execfail off
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-030
+
+Bug-Reported-by: Roman Rakus <rrakus@redhat.com>
+Bug-Reference-ID: <4D7DD91E.7040808@redhat.com>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2011-03/msg00126.html
+
+Bug-Description:
+
+When attempting to glob strings in a multibyte locale, and those strings
+contain invalid multibyte characters that cause mbsnrtowcs to return 0,
+the globbing code loops infinitely.
+
+Patch (apply with `patch -p0'):
+
+--- a/lib/glob/xmbsrtowcs.c
++++ b/lib/glob/xmbsrtowcs.c
+@@ -35,6 +35,8 @@
+
+ #if HANDLE_MULTIBYTE
+
++#define WSBUF_INC 32
++
+ #ifndef FREE
+ # define FREE(x) do { if (x) free (x); } while (0)
+ #endif
+@@ -148,7 +150,7 @@ xdupmbstowcs2 (destp, src)
+ size_t wsbuf_size; /* Size of WSBUF */
+ size_t wcnum; /* Number of wide characters in WSBUF */
+ mbstate_t state; /* Conversion State */
+- size_t wcslength; /* Number of wide characters produced by the conversion. */
++ size_t n, wcslength; /* Number of wide characters produced by the conversion. */
+ const char *end_or_backslash;
+ size_t nms; /* Number of multibyte characters to convert at one time. */
+ mbstate_t tmp_state;
+@@ -171,7 +173,18 @@ xdupmbstowcs2 (destp, src)
+ /* Compute the number of produced wide-characters. */
+ tmp_p = p;
+ tmp_state = state;
+- wcslength = mbsnrtowcs(NULL, &tmp_p, nms, 0, &tmp_state);
++
++ if (nms == 0 && *p == '\\') /* special initial case */
++ nms = wcslength = 1;
++ else
++ wcslength = mbsnrtowcs (NULL, &tmp_p, nms, 0, &tmp_state);
++
++ if (wcslength == 0)
++ {
++ tmp_p = p; /* will need below */
++ tmp_state = state;
++ wcslength = 1; /* take a single byte */
++ }
+
+ /* Conversion failed. */
+ if (wcslength == (size_t)-1)
+@@ -186,7 +199,8 @@ xdupmbstowcs2 (destp, src)
+ {
+ wchar_t *wstmp;
+
+- wsbuf_size = wcnum+wcslength+1; /* 1 for the L'\0' or the potential L'\\' */
++ while (wsbuf_size < wcnum+wcslength+1) /* 1 for the L'\0' or the potential L'\\' */
++ wsbuf_size += WSBUF_INC;
+
+ wstmp = (wchar_t *) realloc (wsbuf, wsbuf_size * sizeof (wchar_t));
+ if (wstmp == NULL)
+@@ -199,10 +213,18 @@ xdupmbstowcs2 (destp, src)
+ }
+
+ /* Perform the conversion. This is assumed to return 'wcslength'.
+- * It may set 'p' to NULL. */
+- mbsnrtowcs(wsbuf+wcnum, &p, nms, wsbuf_size-wcnum, &state);
++ It may set 'p' to NULL. */
++ n = mbsnrtowcs(wsbuf+wcnum, &p, nms, wsbuf_size-wcnum, &state);
+
+- wcnum += wcslength;
++ /* Compensate for taking single byte on wcs conversion failure above. */
++ if (wcslength == 1 && (n == 0 || n == (size_t)-1))
++ {
++ state = tmp_state;
++ p = tmp_p;
++ wsbuf[wcnum++] = *p++;
++ }
++ else
++ wcnum += wcslength;
+
+ if (mbsinit (&state) && (p != NULL) && (*p == '\\'))
+ {
+@@ -230,8 +252,6 @@ xdupmbstowcs2 (destp, src)
+ If conversion is failed, the return value is (size_t)-1 and the values
+ of DESTP and INDICESP are NULL. */
+
+-#define WSBUF_INC 32
+-
+ size_t
+ xdupmbstowcs (destp, indicesp, src)
+ wchar_t **destp; /* Store the pointer to the wide character string */
+--- a/lib/glob/glob.c
++++ b/lib/glob/glob.c
+@@ -200,8 +200,11 @@ mbskipname (pat, dname, flags)
+ wchar_t *pat_wc, *dn_wc;
+ size_t pat_n, dn_n;
+
++ pat_wc = dn_wc = (wchar_t *)NULL;
++
+ pat_n = xdupmbstowcs (&pat_wc, NULL, pat);
+- dn_n = xdupmbstowcs (&dn_wc, NULL, dname);
++ if (pat_n != (size_t)-1)
++ dn_n = xdupmbstowcs (&dn_wc, NULL, dname);
+
+ ret = 0;
+ if (pat_n != (size_t)-1 && dn_n !=(size_t)-1)
+@@ -221,6 +224,8 @@ mbskipname (pat, dname, flags)
+ (pat_wc[0] != L'\\' || pat_wc[1] != L'.'))
+ ret = 1;
+ }
++ else
++ ret = skipname (pat, dname, flags);
+
+ FREE (pat_wc);
+ FREE (dn_wc);
+@@ -266,8 +271,11 @@ wdequote_pathname (pathname)
+ /* Convert the strings into wide characters. */
+ n = xdupmbstowcs (&wpathname, NULL, pathname);
+ if (n == (size_t) -1)
+- /* Something wrong. */
+- return;
++ {
++ /* Something wrong. Fall back to single-byte */
++ udequote_pathname (pathname);
++ return;
++ }
+ orig_wpathname = wpathname;
+
+ for (i = j = 0; wpathname && wpathname[i]; )
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 29
++#define PATCHLEVEL 30
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-031
+
+Bug-Reported-by: Max Horn <max@quendi.de>
+Bug-Reference-ID: <20CC5C60-07C3-4E41-9817-741E48D407C5@quendi.de>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-readline/2012-06/msg00005.html
+
+Bug-Description:
+
+A change between bash-4.1 and bash-4.2 to prevent the readline input hook
+from being called too frequently had the side effect of causing delays
+when reading pasted input on systems such as Mac OS X. This patch fixes
+those delays while retaining the bash-4.2 behavior.
+
+Patch (apply with `patch -p0'):
+
+--- a/lib/readline/input.c
++++ b/lib/readline/input.c
+@@ -409,7 +409,7 @@ rl_clear_pending_input ()
+ int
+ rl_read_key ()
+ {
+- int c;
++ int c, r;
+
+ rl_key_sequence_length++;
+
+@@ -429,14 +429,18 @@ rl_read_key ()
+ {
+ while (rl_event_hook)
+ {
+- if (rl_gather_tyi () < 0) /* XXX - EIO */
++ if (rl_get_char (&c) != 0)
++ break;
++
++ if ((r = rl_gather_tyi ()) < 0) /* XXX - EIO */
+ {
+ rl_done = 1;
+ return ('\n');
+ }
++ else if (r == 1) /* read something */
++ continue;
++
+ RL_CHECK_SIGNALS ();
+- if (rl_get_char (&c) != 0)
+- break;
+ if (rl_done) /* XXX - experimental */
+ return ('\n');
+ (*rl_event_hook) ();
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 30
++#define PATCHLEVEL 31
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-032
+
+Bug-Reported-by: Ruediger Kuhlmann <RKuhlmann@orga-systems.com>
+Bug-Reference-ID: <OFDE975207.0C3622E5-ONC12579F3.00361A06-C12579F3.00365E39@orga-systems.com>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2012-05/msg00010.html
+
+Bug-Description:
+
+Bash-4.2 has problems with DEL characters in the expanded value of variables
+used in the same quoted string as variables that expand to nothing.
+
+Patch (apply with `patch -p0'):
+
+--- a/subst.c
++++ b/subst.c
+@@ -8151,6 +8151,14 @@ add_string:
+ temp = tword->word;
+ dispose_word_desc (tword);
+
++ /* Kill quoted nulls; we will add them back at the end of
++ expand_word_internal if nothing else in the string */
++ if (had_quoted_null && temp && QUOTED_NULL (temp))
++ {
++ FREE (temp);
++ temp = (char *)NULL;
++ }
++
+ goto add_string;
+ break;
+
+@@ -8555,7 +8563,7 @@ finished_with_string:
+ tword->flags |= W_NOEXPAND; /* XXX */
+ if (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
+ tword->flags |= W_QUOTED;
+- if (had_quoted_null)
++ if (had_quoted_null && QUOTED_NULL (istring))
+ tword->flags |= W_HASQUOTEDNULL;
+ list = make_word_list (tword, (WORD_LIST *)NULL);
+ }
+@@ -8586,7 +8594,7 @@ finished_with_string:
+ tword->flags |= W_NOGLOB;
+ if (word->flags & W_NOEXPAND)
+ tword->flags |= W_NOEXPAND;
+- if (had_quoted_null)
++ if (had_quoted_null && QUOTED_NULL (istring))
+ tword->flags |= W_HASQUOTEDNULL; /* XXX */
+ list = make_word_list (tword, (WORD_LIST *)NULL);
+ }
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 31
++#define PATCHLEVEL 32
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-033
+
+Bug-Reported-by: David Leverton <levertond@googlemail.com>
+Bug-Reference-ID: <4FCCE737.1060603@googlemail.com>
+Bug-Reference-URL:
+
+Bug-Description:
+
+Bash uses a static buffer when expanding the /dev/fd prefix for the test
+and conditional commands, among other uses, when it should use a dynamic
+buffer to avoid buffer overflow.
+
+Patch (apply with `patch -p0'):
+
+--- a/lib/sh/eaccess.c
++++ b/lib/sh/eaccess.c
+@@ -82,6 +82,8 @@ sh_stat (path, finfo)
+ const char *path;
+ struct stat *finfo;
+ {
++ static char *pbuf = 0;
++
+ if (*path == '\0')
+ {
+ errno = ENOENT;
+@@ -106,7 +108,7 @@ sh_stat (path, finfo)
+ trailing slash. Make sure /dev/fd/xx really uses DEV_FD_PREFIX/xx.
+ On most systems, with the notable exception of linux, this is
+ effectively a no-op. */
+- char pbuf[32];
++ pbuf = xrealloc (pbuf, sizeof (DEV_FD_PREFIX) + strlen (path + 8));
+ strcpy (pbuf, DEV_FD_PREFIX);
+ strcat (pbuf, path + 8);
+ return (stat (pbuf, finfo));
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 32
++#define PATCHLEVEL 33
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-034
+
+Bug-Reported-by: "Davide Brini" <dave_br@gmx.com>
+Bug-Reference-ID: <20120604164154.69781EC04B@imaps.oficinas.atrapalo.com>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2012-06/msg00030.html
+
+Bug-Description:
+
+In bash-4.2, the history code would inappropriately add a semicolon to
+multi-line compound array assignments when adding them to the history.
+
+Patch (apply with `patch -p0'):
+
+--- a/parse.y
++++ b/parse.y
+@@ -4900,6 +4900,9 @@ history_delimiting_chars (line)
+ return (current_command_line_count == 2 ? "\n" : "");
+ }
+
++ if (parser_state & PST_COMPASSIGN)
++ return (" ");
++
+ /* First, handle some special cases. */
+ /*(*/
+ /* If we just read `()', assume it's a function definition, and don't
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 33
++#define PATCHLEVEL 34
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-035
+
+Bug-Reported-by: Dan Douglas <ormaaj@gmail.com>
+Bug-Reference-ID: <2766482.Ksm3GrSoYi@smorgbox>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2012-06/msg00071.html
+
+Bug-Description:
+
+When given a number of lines to read, `mapfile -n lines' reads one too many.
+
+Patch (apply with `patch -p0'):
+
+--- a/builtins/mapfile.def
++++ b/builtins/mapfile.def
+@@ -195,13 +195,9 @@ mapfile (fd, line_count_goal, origin, ns
+ /* Reset the buffer for bash own stream */
+ interrupt_immediately++;
+ for (array_index = origin, line_count = 1;
+- zgetline (fd, &line, &line_length, unbuffered_read) != -1;
+- array_index++, line_count++)
++ zgetline (fd, &line, &line_length, unbuffered_read) != -1;
++ array_index++)
+ {
+- /* Have we exceeded # of lines to store? */
+- if (line_count_goal != 0 && line_count > line_count_goal)
+- break;
+-
+ /* Remove trailing newlines? */
+ if (flags & MAPF_CHOP)
+ do_chop (line);
+@@ -217,6 +213,11 @@ mapfile (fd, line_count_goal, origin, ns
+ }
+
+ bind_array_element (entry, array_index, line, 0);
++
++ /* Have we exceeded # of lines to store? */
++ line_count++;
++ if (line_count_goal != 0 && line_count > line_count_goal)
++ break;
+ }
+
+ xfree (line);
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 34
++#define PATCHLEVEL 35
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-036
+
+Bug-Reported-by: gregrwm <backuppc-users@whitleymott.net>
+Bug-Reference-ID: <CAD+dB9B4JG+qUwZBQUwiQmVt0j6NDn=DDTxr9R+nkA8DL4KLJA@mail.gmail.com>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2012-05/msg00108.html
+
+Bug-Description:
+
+Bash-4.2 produces incorrect word splitting results when expanding
+double-quoted $@ in the same string as and adjacent to other variable
+expansions. The $@ should be split, the other expansions should not.
+
+Patch (apply with `patch -p0'):
+
+--- a/subst.c
++++ b/subst.c
+@@ -7922,7 +7922,7 @@ expand_word_internal (word, quoted, isex
+
+ /* State flags */
+ int had_quoted_null;
+- int has_dollar_at;
++ int has_dollar_at, temp_has_dollar_at;
+ int tflag;
+ int pflags; /* flags passed to param_expand */
+
+@@ -8127,13 +8127,14 @@ add_string:
+ if (expanded_something)
+ *expanded_something = 1;
+
+- has_dollar_at = 0;
++ temp_has_dollar_at = 0;
+ pflags = (word->flags & W_NOCOMSUB) ? PF_NOCOMSUB : 0;
+ if (word->flags & W_NOSPLIT2)
+ pflags |= PF_NOSPLIT2;
+ tword = param_expand (string, &sindex, quoted, expanded_something,
+- &has_dollar_at, "ed_dollar_at,
++ &temp_has_dollar_at, "ed_dollar_at,
+ &had_quoted_null, pflags);
++ has_dollar_at += temp_has_dollar_at;
+
+ if (tword == &expand_wdesc_error || tword == &expand_wdesc_fatal)
+ {
+@@ -8274,9 +8275,10 @@ add_twochars:
+
+ temp = (char *)NULL;
+
+- has_dollar_at = 0;
++ temp_has_dollar_at = 0; /* XXX */
+ /* Need to get W_HASQUOTEDNULL flag through this function. */
+- list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &has_dollar_at, (int *)NULL);
++ list = expand_word_internal (tword, Q_DOUBLE_QUOTES, 0, &temp_has_dollar_at, (int *)NULL);
++ has_dollar_at += temp_has_dollar_at;
+
+ if (list == &expand_word_error || list == &expand_word_fatal)
+ {
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 35
++#define PATCHLEVEL 36
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-037
+
+Bug-Reported-by: Jakub Filak
+Bug-Reference-ID:
+Bug-Reference-URL: https://bugzilla.redhat.com/show_bug.cgi?id=813289
+
+Bug-Description:
+
+Attempting to redo (using `.') the vi editing mode `cc', `dd', or `yy'
+commands leads to an infinite loop.
+
+Patch (apply with `patch -p0'):
+
+--- a/lib/readline/vi_mode.c
++++ b/lib/readline/vi_mode.c
+@@ -1234,11 +1234,19 @@ rl_vi_delete_to (count, key)
+ _rl_vimvcxt->motion = '$';
+ r = rl_domove_motion_callback (_rl_vimvcxt);
+ }
+- else if (vi_redoing)
++ else if (vi_redoing && _rl_vi_last_motion != 'd') /* `dd' is special */
+ {
+ _rl_vimvcxt->motion = _rl_vi_last_motion;
+ r = rl_domove_motion_callback (_rl_vimvcxt);
+ }
++ else if (vi_redoing) /* handle redoing `dd' here */
++ {
++ _rl_vimvcxt->motion = _rl_vi_last_motion;
++ rl_mark = rl_end;
++ rl_beg_of_line (1, key);
++ RL_UNSETSTATE (RL_STATE_VIMOTION);
++ r = vidomove_dispatch (_rl_vimvcxt);
++ }
+ #if defined (READLINE_CALLBACKS)
+ else if (RL_ISSTATE (RL_STATE_CALLBACK))
+ {
+@@ -1316,11 +1324,19 @@ rl_vi_change_to (count, key)
+ _rl_vimvcxt->motion = '$';
+ r = rl_domove_motion_callback (_rl_vimvcxt);
+ }
+- else if (vi_redoing)
++ else if (vi_redoing && _rl_vi_last_motion != 'c') /* `cc' is special */
+ {
+ _rl_vimvcxt->motion = _rl_vi_last_motion;
+ r = rl_domove_motion_callback (_rl_vimvcxt);
+ }
++ else if (vi_redoing) /* handle redoing `cc' here */
++ {
++ _rl_vimvcxt->motion = _rl_vi_last_motion;
++ rl_mark = rl_end;
++ rl_beg_of_line (1, key);
++ RL_UNSETSTATE (RL_STATE_VIMOTION);
++ r = vidomove_dispatch (_rl_vimvcxt);
++ }
+ #if defined (READLINE_CALLBACKS)
+ else if (RL_ISSTATE (RL_STATE_CALLBACK))
+ {
+@@ -1377,6 +1393,19 @@ rl_vi_yank_to (count, key)
+ _rl_vimvcxt->motion = '$';
+ r = rl_domove_motion_callback (_rl_vimvcxt);
+ }
++ else if (vi_redoing && _rl_vi_last_motion != 'y') /* `yy' is special */
++ {
++ _rl_vimvcxt->motion = _rl_vi_last_motion;
++ r = rl_domove_motion_callback (_rl_vimvcxt);
++ }
++ else if (vi_redoing) /* handle redoing `yy' here */
++ {
++ _rl_vimvcxt->motion = _rl_vi_last_motion;
++ rl_mark = rl_end;
++ rl_beg_of_line (1, key);
++ RL_UNSETSTATE (RL_STATE_VIMOTION);
++ r = vidomove_dispatch (_rl_vimvcxt);
++ }
+ #if defined (READLINE_CALLBACKS)
+ else if (RL_ISSTATE (RL_STATE_CALLBACK))
+ {
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 36
++#define PATCHLEVEL 37
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-038
+
+Bug-Reported-by: armandsl@gmail.com
+Bug-Reference-ID: <20120822112810.8D14920040@windmill.latviatours.lv>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2012-08/msg00049.html
+
+Bug-Description:
+
+If a backslash-newline (which is removed) with no other input is given as
+input to `read', the shell tries to dereference a null pointer and seg faults.
+
+Patch (apply with `patch -p0'):
+
+--- a/builtins/read.def
++++ b/builtins/read.def
+@@ -791,7 +791,7 @@ assign_vars:
+ }
+ #endif
+
+- if (saw_escape)
++ if (saw_escape && input_string && *input_string)
+ {
+ t = dequote_string (input_string);
+ var = bind_read_variable (list->word->word, t);
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 37
++#define PATCHLEVEL 38
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-039
+
+Bug-Reported-by: Dan Douglas <ormaaj@gmail.com>
+Bug-Reference-ID: <1498458.MpVlmOXDB7@smorgbox>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2012-09/msg00008.html
+
+Bug-Description:
+
+Under certain circumstances, bash attempts to expand variables in arithmetic
+expressions even when evaluation is being suppressed.
+
+Patch (apply with `patch -p0'):
+
+--- a/expr.c
++++ b/expr.c
+@@ -1009,6 +1009,12 @@ expr_streval (tok, e, lvalue)
+ arrayind_t ind;
+ #endif
+
++/*itrace("expr_streval: %s: noeval = %d", tok, noeval);*/
++ /* If we are suppressing evaluation, just short-circuit here instead of
++ going through the rest of the evaluator. */
++ if (noeval)
++ return (0);
++
+ /* [[[[[ */
+ #if defined (ARRAY_VARS)
+ v = (e == ']') ? array_variable_part (tok, (char **)0, (int *)0) : find_variable (tok);
+@@ -1182,6 +1188,10 @@ readtok ()
+ #endif /* ARRAY_VARS */
+
+ *cp = '\0';
++ /* XXX - watch out for pointer aliasing issues here */
++ if (curlval.tokstr && curlval.tokstr == tokstr)
++ init_lvalue (&curlval);
++
+ FREE (tokstr);
+ tokstr = savestring (tp);
+ *cp = c;
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 38
++#define PATCHLEVEL 39
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-040
+
+Bug-Reported-by: Andrey Zaitsev <jstcdr@gmail.com>
+Bug-Reference-ID: <CAEZVQT5PJ1Mb_Zh8LT5qz8sv+-9Q6hGfQ5DU9ZxdJ+gV7xBUaQ@mail.gmail.com>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2012-04/msg00144.html
+
+Bug-Description:
+
+Output redirection applied to builtin commands missed I/O errors if
+they happened when the file descriptor was closed, rather than on write
+(e.g., like with an out-of-space error on a remote NFS file system).
+
+Patch (apply with `patch -p0'):
+
+--- a/redir.c
++++ b/redir.c
+@@ -1091,10 +1091,12 @@ do_redirection_internal (redirect, flags
+
+ #if defined (BUFFERED_INPUT)
+ check_bash_input (redirector);
+- close_buffered_fd (redirector);
++ r = close_buffered_fd (redirector);
+ #else /* !BUFFERED_INPUT */
+- close (redirector);
++ r = close (redirector);
+ #endif /* !BUFFERED_INPUT */
++ if (r < 0 && (flags & RX_INTERNAL) && (errno == EIO || errno == ENOSPC))
++ REDIRECTION_ERROR (r, errno, -1);
+ }
+ break;
+
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 39
++#define PATCHLEVEL 40
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-041
+
+Bug-Reported-by: Andrey Borzenkov <arvidjaar@gmail.com>
+Bug-Reference-ID: <20121202205200.2134478e@opensuse.site>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2012-12/msg00008.html
+
+Bug-Description:
+
+Process substitution incorrectly inherited a flag that inhibited using the
+(local) temporary environment for variable lookups if it was providing
+the filename to a redirection. The intent the flag is to enforce the
+Posix command expansion ordering rules.
+
+Patch (apply with `patch -p0'):
+
+--- a/subst.c
++++ b/subst.c
+@@ -5124,6 +5124,10 @@ process_substitute (string, open_for_rea
+ dev_fd_list[parent_pipe_fd] = 0;
+ #endif /* HAVE_DEV_FD */
+
++ /* subshells shouldn't have this flag, which controls using the temporary
++ environment for variable lookups. */
++ expanding_redir = 0;
++
+ result = parse_and_execute (string, "process substitution", (SEVAL_NONINT|SEVAL_NOHIST));
+
+ #if !defined (HAVE_DEV_FD)
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 40
++#define PATCHLEVEL 41
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-042
+
+Bug-Reported-by: Adam Pippin <adam@gp-inc.ca>
+Bug-Reference-ID: <CAPYbNHr6ucZFOoWsRdUJj6KP3Ju0j1bkESa_cmb7iU+kZwdVpg@mail.gmail.com>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2012-11/msg00087.html
+
+Bug-Description:
+
+Compilation failed after specifying the `--enable-minimal-config' option to
+configure (more specifically, specifying `--disable-alias').
+
+Patch (apply with `patch -p0'):
+
+--- a/parse.y
++++ b/parse.y
+@@ -2393,6 +2393,7 @@ pop_alias:
+ is the last character). If it's not the last character, we need
+ to consume the quoted newline and move to the next character in
+ the expansion. */
++#if defined (ALIAS)
+ if (expanding_alias () && shell_input_line[shell_input_line_index+1] == '\0')
+ {
+ uc = 0;
+@@ -2403,7 +2404,8 @@ pop_alias:
+ shell_input_line_index++; /* skip newline */
+ goto next_alias_char; /* and get next character */
+ }
+- else
++ else
++#endif
+ goto restart_read;
+ }
+
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 41
++#define PATCHLEVEL 42
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-043
+
+Bug-Reported-by: konsolebox <konsolebox@gmail.com>
+Bug-Reference-ID: <CAJnmqwZuGKLgMsMwxRK4LL+2NN+HgvmKzrnode99QBGrcgX1Lw@mail.gmail.com>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2013-01/msg00138.html
+
+Bug-Description:
+
+When SIGCHLD is trapped, and a SIGCHLD trap handler runs when a pending
+`read -t' invocation times out and generates SIGALRM, bash can crash with
+a segmentation fault.
+
+Patch (apply with `patch -p0'):
+
+--- a/builtins/read.def
++++ b/builtins/read.def
+@@ -385,10 +385,20 @@ read_builtin (list)
+ {
+ /* Tricky. The top of the unwind-protect stack is the free of
+ input_string. We want to run all the rest and use input_string,
+- so we have to remove it from the stack. */
+- remove_unwind_protect ();
+- run_unwind_frame ("read_builtin");
++ so we have to save input_string temporarily, run the unwind-
++ protects, then restore input_string so we can use it later. */
++
+ input_string[i] = '\0'; /* make sure it's terminated */
++ if (i == 0)
++ {
++ t = (char *)xmalloc (1);
++ t[0] = 0;
++ }
++ else
++ t = savestring (input_string);
++
++ run_unwind_frame ("read_builtin");
++ input_string = t;
+ retval = 128+SIGALRM;
+ goto assign_vars;
+ }
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 42
++#define PATCHLEVEL 43
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-044
+
+Bug-Reported-by: "Dashing" <dashing@hushmail.com>
+Bug-Reference-ID: <20130211175049.D90786F446@smtp.hushmail.com>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2013-02/msg00030.html
+
+Bug-Description:
+
+When converting a multibyte string to a wide character string as part of
+pattern matching, bash does not handle the end of the string correctly,
+causing the search for the NUL to go beyond the end of the string and
+reference random memory. Depending on the contents of that memory, bash
+can produce errors or crash.
+
+Patch (apply with `patch -p0'):
+
+--- a/lib/glob/xmbsrtowcs.c
++++ b/lib/glob/xmbsrtowcs.c
+@@ -216,12 +216,24 @@ xdupmbstowcs2 (destp, src)
+ It may set 'p' to NULL. */
+ n = mbsnrtowcs(wsbuf+wcnum, &p, nms, wsbuf_size-wcnum, &state);
+
++ if (n == 0 && p == 0)
++ {
++ wsbuf[wcnum] = L'\0';
++ break;
++ }
++
+ /* Compensate for taking single byte on wcs conversion failure above. */
+ if (wcslength == 1 && (n == 0 || n == (size_t)-1))
+ {
+ state = tmp_state;
+ p = tmp_p;
+- wsbuf[wcnum++] = *p++;
++ wsbuf[wcnum] = *p;
++ if (*p == 0)
++ break;
++ else
++ {
++ wcnum++; p++;
++ }
+ }
+ else
+ wcnum += wcslength;
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 43
++#define PATCHLEVEL 44
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-045
+
+Bug-Reported-by: Stephane Chazelas <stephane.chazelas@gmail.com>
+Bug-Reference-ID: <20130218195539.GA9620@chaz.gmail.com>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2013-02/msg00080.html
+
+Bug-Description:
+
+The <&n- and >&n- redirections, which move one file descriptor to another,
+leave the file descriptor closed when applied to builtins or compound
+commands.
+
+Patch (apply with `patch -p0'):
+
+--- a/redir.c
++++ b/redir.c
+@@ -1007,6 +1007,16 @@ do_redirection_internal (redirect, flags
+ close (redirector);
+ REDIRECTION_ERROR (r, errno, -1);
+ }
++ if ((flags & RX_UNDOABLE) && (ri == r_move_input || ri == r_move_output))
++ {
++ /* r_move_input and r_move_output add an additional close()
++ that needs to be undone */
++ if (fcntl (redirector, F_GETFD, 0) != -1)
++ {
++ r = add_undo_redirect (redir_fd, r_close_this, -1);
++ REDIRECTION_ERROR (r, errno, -1);
++ }
++ }
+ #if defined (BUFFERED_INPUT)
+ check_bash_input (redirector);
+ #endif
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 44
++#define PATCHLEVEL 45
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-046
+
+Bug-Reported-by: "Theodoros V. Kalamatianos" <thkala@gmail.com>
+Bug-Reference-ID: <20140112011131.GE17667@infinity.metashade.com>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2014-01/msg00044.html
+
+Bug-Description:
+
+Bash-4.2 patch 32 introduced a problem with "$@" and arrays expanding empty
+positional parameters or array elements when using substring expansion,
+pattern substitution, or case modfication. The empty parameters or array
+elements are removed instead of expanding to empty strings ("").
+
+Patch (apply with `patch -p0'):
+
+--- a/subst.c
++++ b/subst.c
+@@ -7242,7 +7242,13 @@ parameter_brace_expand (string, indexp,
+
+ ret = alloc_word_desc ();
+ ret->word = temp1;
+- if (temp1 && QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
++ /* We test quoted_dollar_atp because we want variants with double-quoted
++ "$@" to take a different code path. In fact, we make sure at the end
++ of expand_word_internal that we're only looking at these flags if
++ quoted_dollar_at == 0. */
++ if (temp1 &&
++ (quoted_dollar_atp == 0 || *quoted_dollar_atp == 0) &&
++ QUOTED_NULL (temp1) && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
+ ret->flags |= W_QUOTED|W_HASQUOTEDNULL;
+ return ret;
+ }
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 45
++#define PATCHLEVEL 46
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-047
+
+Bug-Reported-by: Matthew Riley <mattdr@google.com>
+Bug-Reference-ID: <CA+NEdkwP3gw+gbcF5+xnR1pvcuzb1mDVzvmuJOpHRGHA9T7VFg@mail.gmail.com>
+Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2013-03/msg00047.html
+
+Bug-Description:
+
+The function that shortens pathnames for $PS1 according to the value of
+$PROMPT_DIRTRIM uses memcpy on potentially-overlapping regions of memory,
+when it should use memmove. The result is garbled pathnames in prompt
+strings.
+
+Patch (apply with `patch -p0'):
+
+--- a/general.c
++++ b/general.c
+@@ -766,7 +766,7 @@ trim_pathname (name, maxlen)
+ *nbeg++ = '.';
+
+ nlen = nend - ntail;
+- memcpy (nbeg, ntail, nlen);
++ memmove (nbeg, ntail, nlen);
+ nbeg[nlen] = '\0';
+
+ return name;
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 46
++#define PATCHLEVEL 47
+
+ #endif /* _PATCHLEVEL_H_ */
--- /dev/null
+ BASH PATCH REPORT
+ =================
+
+Bash-Release: 4.2
+Patch-ID: bash42-048
+
+Bug-Reported-by: Stephane Chazelas <stephane.chazelas@gmail.com>
+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'):
+
+--- a/builtins/common.h
++++ b/builtins/common.h
+@@ -35,6 +35,8 @@
+ #define SEVAL_NOLONGJMP 0x040
+
+ /* 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 */
+ #define CDESC_REUSABLE 0x004 /* command -v */
+--- a/builtins/evalstring.c
++++ b/builtins/evalstring.c
+@@ -261,6 +261,14 @@ parse_and_execute (string, from_file, fl
+ {
+ 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");
+ add_unwind_protect (dispose_fd_bitmap, bitmap);
+@@ -321,6 +329,9 @@ parse_and_execute (string, from_file, fl
+ dispose_command (command);
+ dispose_fd_bitmap (bitmap);
+ discard_unwind_frame ("pe_dispose");
++
++ if (flags & SEVAL_ONECMD)
++ break;
+ }
+ }
+ else
+--- a/variables.c
++++ b/variables.c
+@@ -347,12 +347,10 @@ initialize_shell_variables (env, privmod
+ temp_string[char_index] = ' ';
+ 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';
++ /* 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))
+ {
+@@ -361,10 +359,6 @@ initialize_shell_variables (env, privmod
+ }
+ 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)
+ # if 0
+--- a/patchlevel.h
++++ b/patchlevel.h
+@@ -25,6 +25,6 @@
+ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
+ looks for to find the patch level (for the sccs version string). */
+
+-#define PATCHLEVEL 47
++#define PATCHLEVEL 48
+
+ #endif /* _PATCHLEVEL_H_ */