[oe] [meta-oe][zeus][PATCH] bash: Fix CVE-2019-18276

Khem Raj raj.khem at gmail.com
Fri Jan 17 18:08:04 UTC 2020


On 1/16/20 10:08 PM, De Huo wrote:
> An issue was discovered in disable_priv_mode in shell.c in GNU Bash through 5.0 patch 11.
> By default, if Bash is run with its effective UID not equal to its real UID,
> it will drop privileges by setting its effective UID to its real UID.
> However, it does so incorrectly. On Linux and other systems that support "saved UID" functionality,
> the saved UID is not dropped. An attacker with command execution in the shell can use "enable -f" for
> runtime loading of a new builtin, which can be a shared object that calls setuid() and therefore
> regains privileges. However, binaries running with an effective UID of 0 are unaffected.
> 
> Backport the CVE patche from https://github.com/bminor/bash/commit/
> 951bdaad7a18cc0dc1036bba86b18b90874d39ff to fix CVE-2019-18276
> 

Thanks Chet, please send this patch to openembedded-core mailing list. 
Since this package is part of core layer which has its own development 
layer.

> Signed-off-by: Chet Ramey <chet.ramey at case.edu>
> Signed-off-by: De Huo <De.Huo at windriver.com>
> ---
>   .../bash/bash/bash-CVE-2019-18276.patch       | 402 ++++++++++++++++++
>   meta/recipes-extended/bash/bash_5.0.bb        |   1 +
>   2 files changed, 403 insertions(+)
>   create mode 100644 meta/recipes-extended/bash/bash/bash-CVE-2019-18276.patch
> 
> diff --git a/meta/recipes-extended/bash/bash/bash-CVE-2019-18276.patch b/meta/recipes-extended/bash/bash/bash-CVE-2019-18276.patch
> new file mode 100644
> index 0000000000..78dcc1b636
> --- /dev/null
> +++ b/meta/recipes-extended/bash/bash/bash-CVE-2019-18276.patch
> @@ -0,0 +1,402 @@
> +From 951bdaad7a18cc0dc1036bba86b18b90874d39ff Mon Sep 17 00:00:00 2001
> +From: Chet Ramey <chet.ramey at case.edu>
> +Date: Mon, 1 Jul 2019 09:03:53 -0400
> +Subject: [PATCH] commit bash-20190628 snapshot
> +
> +An issue was discovered in disable_priv_mode in shell.c in GNU Bash through 5.0 patch 11.
> +By default, if Bash is run with its effective UID not equal to its real UID,
> +it will drop privileges by setting its effective UID to its real UID.
> +However, it does so incorrectly. On Linux and other systems that support "saved UID" functionality,
> +the saved UID is not dropped. An attacker with command execution in the shell can use "enable -f" for
> +runtime loading of a new builtin, which can be a shared object that calls setuid() and therefore
> +regains privileges. However, binaries running with an effective UID of 0 are unaffected.
> +
> +Upstream-Status: Backport [https://github.com/bminor/bash/commit/951bdaad7a18cc0dc1036bba86b18b90874d39ff]
> +CVE: CVE-2019-18276
> +Signed-off-by: Chet Ramey <chet.ramey at case.edu>
> +Signed-off-by: De Huo <De.Huo at windriver.com>
> +---
> + MANIFEST          |  2 ++
> + bashline.c        | 50 +-------------------------------------------------
> + builtins/help.def |  2 +-
> + config.h.in       | 10 +++++++++-
> + configure         | 11 +++++++++++
> + configure.ac      |  1 +
> + doc/bash.1        |  3 ++-
> + doc/bashref.texi  |  3 ++-
> + lib/glob/glob.c   |  5 ++++-
> + pathexp.c         | 16 ++++++++++++++--
> + shell.c           |  8 ++++++++
> + tests/glob.tests  |  2 ++
> + tests/glob6.sub   | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> + tests/glob7.sub   | 11 +++++++++++
> + 14 files changed, 122 insertions(+), 56 deletions(-)
> + create mode 100644 tests/glob6.sub
> + create mode 100644 tests/glob7.sub
> +
> +diff --git a/MANIFEST b/MANIFEST
> +index 03de221..f9ccad7 100644
> +--- a/MANIFEST
> ++++ b/MANIFEST
> +@@ -1037,6 +1037,8 @@ tests/extglob3.tests	f
> + tests/extglob3.right	f
> + tests/extglob4.sub	f
> + tests/extglob5.sub	f
> ++tests/glob6.sub		f
> ++tests/glob7.sub		f
> + tests/func.tests	f
> + tests/func.right	f
> + tests/func1.sub		f
> +diff --git a/bashline.c b/bashline.c
> +index 824ea9d..d86b47d 100644
> +--- a/bashline.c
> ++++ b/bashline.c
> +@@ -3718,55 +3718,7 @@ static int
> + completion_glob_pattern (string)
> +      char *string;
> + {
> +-  register int c;
> +-  char *send;
> +-  int open;
> +-
> +-  DECLARE_MBSTATE;
> +-
> +-  open = 0;
> +-  send = string + strlen (string);
> +-
> +-  while (c = *string++)
> +-    {
> +-      switch (c)
> +-	{
> +-	case '?':
> +-	case '*':
> +-	  return (1);
> +-
> +-	case '[':
> +-	  open++;
> +-	  continue;
> +-
> +-	case ']':
> +-	  if (open)
> +-	    return (1);
> +-	  continue;
> +-
> +-	case '+':
> +-	case '@':
> +-	case '!':
> +-	  if (*string == '(')	/*)*/
> +-	    return (1);
> +-	  continue;
> +-
> +-	case '\\':
> +-	  if (*string++ == 0)
> +-	    return (0);	 	
> +-	}
> +-
> +-      /* Advance one fewer byte than an entire multibyte character to
> +-	 account for the auto-increment in the loop above. */
> +-#ifdef HANDLE_MULTIBYTE
> +-      string--;
> +-      ADVANCE_CHAR_P (string, send - string);
> +-      string++;
> +-#else
> +-      ADVANCE_CHAR_P (string, send - string);
> +-#endif
> +-    }
> +-  return (0);
> ++  return (glob_pattern_p (string) == 1);
> + }
> +
> + static char *globtext;
> +diff --git a/builtins/help.def b/builtins/help.def
> +index 006c4b5..92f9b38 100644
> +--- a/builtins/help.def
> ++++ b/builtins/help.def
> +@@ -128,7 +128,7 @@ help_builtin (list)
> +
> +   /* We should consider making `help bash' do something. */
> +
> +-  if (glob_pattern_p (list->word->word))
> ++  if (glob_pattern_p (list->word->word) == 1)
> +     {
> +       printf ("%s", ngettext ("Shell commands matching keyword `", "Shell commands matching keywords `", (list->next ? 2 : 1)));
> +       print_word_list (list, ", ");
> +diff --git a/config.h.in b/config.h.in
> +index 8554aec..ad4b1e8 100644
> +--- a/config.h.in
> ++++ b/config.h.in
> +@@ -1,6 +1,6 @@
> + /* config.h -- Configuration file for bash. */
> +
> +-/* Copyright (C) 1987-2009,2011-2012 Free Software Foundation, Inc.
> ++/* Copyright (C) 1987-2009,2011-2012,2013-2019 Free Software Foundation, Inc.
> +
> +    This file is part of GNU Bash, the Bourne Again SHell.
> +
> +@@ -807,6 +807,14 @@
> + #undef HAVE_SETREGID
> + #undef HAVE_DECL_SETREGID
> +
> ++/* Define if you have the setregid function.  */
> ++#undef HAVE_SETRESGID
> ++#undef HAVE_DECL_SETRESGID
> ++
> ++/* Define if you have the setresuid function.  */
> ++#undef HAVE_SETRESUID
> ++#undef HAVE_DECL_SETRESUID
> ++
> + /* Define if you have the setvbuf function.  */
> + #undef HAVE_SETVBUF
> +
> +diff --git a/configure b/configure
> +index 2f62662..b3321c9 100755
> +--- a/configure
> ++++ b/configure
> +@@ -10281,6 +10281,17 @@ cat >>confdefs.h <<_ACEOF
> + #define HAVE_DECL_SETREGID $ac_have_decl
> + _ACEOF
> +
> ++ac_fn_c_check_decl "$LINENO" "" "ac_cv_have_decl_" "$ac_includes_default"
> ++if test "x$ac_cv_have_decl_" = xyes; then :
> ++  ac_have_decl=1
> ++else
> ++  ac_have_decl=0
> ++fi
> ++
> ++cat >>confdefs.h <<_ACEOF
> ++#define HAVE_DECL_ $ac_have_decl
> ++_ACEOF
> ++(setresuid, setresgid)
> + ac_fn_c_check_decl "$LINENO" "strcpy" "ac_cv_have_decl_strcpy" "$ac_includes_default"
> + if test "x$ac_cv_have_decl_strcpy" = xyes; then :
> +   ac_have_decl=1
> +diff --git a/configure.ac b/configure.ac
> +index 52b4cdb..549adef 100644
> +--- a/configure.ac
> ++++ b/configure.ac
> +@@ -810,6 +810,7 @@ AC_CHECK_DECLS([confstr])
> + AC_CHECK_DECLS([printf])
> + AC_CHECK_DECLS([sbrk])
> + AC_CHECK_DECLS([setregid])
> ++AC_CHECK_DECLS[(setresuid, setresgid])
> + AC_CHECK_DECLS([strcpy])
> + AC_CHECK_DECLS([strsignal])
> +
> +diff --git a/doc/bash.1 b/doc/bash.1
> +index e6cd08d..9e58a0b 100644
> +--- a/doc/bash.1
> ++++ b/doc/bash.1
> +@@ -4681,7 +4681,8 @@ above).
> + .PD
> + .SH "SIMPLE COMMAND EXPANSION"
> + When a simple command is executed, the shell performs the following
> +-expansions, assignments, and redirections, from left to right.
> ++expansions, assignments, and redirections, from left to right, in
> ++the following order.
> + .IP 1.
> + The words that the parser has marked as variable assignments (those
> + preceding the command name) and redirections are saved for later
> +diff --git a/doc/bashref.texi b/doc/bashref.texi
> +index d33cd57..3065126 100644
> +--- a/doc/bashref.texi
> ++++ b/doc/bashref.texi
> +@@ -2964,7 +2964,8 @@ is not specified.  If the file does not exist, it is created.
> + @cindex command expansion
> +
> + When a simple command is executed, the shell performs the following
> +-expansions, assignments, and redirections, from left to right.
> ++expansions, assignments, and redirections, from left to right, in
> ++the following order.
> +
> + @enumerate
> + @item
> +diff --git a/lib/glob/glob.c b/lib/glob/glob.c
> +index 398253b..2eaa33e 100644
> +--- a/lib/glob/glob.c
> ++++ b/lib/glob/glob.c
> +@@ -607,6 +607,7 @@ glob_vector (pat, dir, flags)
> +   register unsigned int i;
> +   int mflags;		/* Flags passed to strmatch (). */
> +   int pflags;		/* flags passed to sh_makepath () */
> ++  int hasglob;		/* return value from glob_pattern_p */
> +   int nalloca;
> +   struct globval *firstmalloc, *tmplink;
> +   char *convfn;
> +@@ -648,10 +649,12 @@ glob_vector (pat, dir, flags)
> +   patlen = (pat && *pat) ? strlen (pat) : 0;
> +
> +   /* If the filename pattern (PAT) does not contain any globbing characters,
> ++     or contains a pattern with only backslash escapes (hasglob == 2),
> +      we can dispense with reading the directory, and just see if there is
> +      a filename `DIR/PAT'.  If there is, and we can access it, just make the
> +      vector to return and bail immediately. */
> +-  if (skip == 0 && glob_pattern_p (pat) == 0)
> ++  hasglob = 0;
> ++  if (skip == 0 && (hasglob = glob_pattern_p (pat)) == 0 || hasglob == 2)
> +     {
> +       int dirlen;
> +       struct stat finfo;
> +diff --git a/pathexp.c b/pathexp.c
> +index c1bf2d8..e6c5392 100644
> +--- a/pathexp.c
> ++++ b/pathexp.c
> +@@ -58,7 +58,10 @@ int extended_glob = EXTGLOB_DEFAULT;
> + /* Control enabling special handling of `**' */
> + int glob_star = 0;
> +
> +-/* Return nonzero if STRING has any unquoted special globbing chars in it.  */
> ++/* Return nonzero if STRING has any unquoted special globbing chars in it.
> ++   This is supposed to be called when pathname expansion is performed, so
> ++   it implements the rules in Posix 2.13.3, specifically that an unquoted
> ++   slash cannot appear in a bracket expression. */
> + int
> + unquoted_glob_pattern_p (string)
> +      register char *string;
> +@@ -85,10 +88,14 @@ unquoted_glob_pattern_p (string)
> + 	  continue;
> +
> + 	case ']':
> +-	  if (open)
> ++	  if (open)		/* XXX - if --open == 0? */
> + 	    return (1);
> + 	  continue;
> +
> ++	case '/':
> ++	  if (open)
> ++	    open = 0;
> ++
> + 	case '+':
> + 	case '@':
> + 	case '!':
> +@@ -106,6 +113,11 @@ unquoted_glob_pattern_p (string)
> + 	      string++;
> + 	      continue;
> + 	    }
> ++	  else if (open && *string == '/')
> ++	    {
> ++	      string++;		/* quoted slashes in bracket expressions are ok */
> ++	      continue;
> ++	    }
> + 	  else if (*string == 0)
> + 	    return (0);
> + 	 	
> +diff --git a/shell.c b/shell.c
> +index a2b2a55..6adabc8 100644
> +--- a/shell.c
> ++++ b/shell.c
> +@@ -1293,7 +1293,11 @@ disable_priv_mode ()
> + {
> +   int e;
> +
> ++#if HAVE_DECL_SETRESUID
> ++  if (setresuid (current_user.uid, current_user.uid, current_user.uid) < 0)
> ++#else
> +   if (setuid (current_user.uid) < 0)
> ++#endif
> +     {
> +       e = errno;
> +       sys_error (_("cannot set uid to %d: effective uid %d"), current_user.uid, current_user.euid);
> +@@ -1302,7 +1306,11 @@ disable_priv_mode ()
> + 	exit (e);
> + #endif
> +     }
> ++#if HAVE_DECL_SETRESGID
> ++  if (setresgid (current_user.gid, current_user.gid, current_user.gid) < 0)
> ++#else
> +   if (setgid (current_user.gid) < 0)
> ++#endif
> +     sys_error (_("cannot set gid to %d: effective gid %d"), current_user.gid, current_user.egid);
> +
> +   current_user.euid = current_user.uid;
> +diff --git a/tests/glob.tests b/tests/glob.tests
> +index 01913bb..fb012f7 100644
> +--- a/tests/glob.tests
> ++++ b/tests/glob.tests
> +@@ -12,6 +12,8 @@ ${THIS_SH} ./glob1.sub
> + ${THIS_SH} ./glob2.sub
> + ${THIS_SH} ./glob3.sub
> + ${THIS_SH} ./glob4.sub
> ++${THIS_SH} ./glob6.sub
> ++${THIS_SH} ./glob7.sub
> +
> + MYDIR=$PWD	# save where we are
> +
> +diff --git a/tests/glob6.sub b/tests/glob6.sub
> +new file mode 100644
> +index 0000000..b099811
> +--- /dev/null
> ++++ b/tests/glob6.sub
> +@@ -0,0 +1,54 @@
> ++# tests of the backslash-in-glob-patterns discussion on the austin-group ML
> ++
> ++: ${TMPDIR:=/var/tmp}
> ++
> ++ORIG=$PWD
> ++GLOBDIR=$TMPDIR/bash-glob-$$
> ++mkdir $GLOBDIR && cd $GLOBDIR
> ++
> ++# does the pattern matcher allow backslashes as escape characters and remove
> ++# them as part of matching?
> ++touch abcdefg
> ++pat='ab\cd*'
> ++printf '<%s>\n' $pat
> ++pat='\.'
> ++printf '<%s>\n' $pat
> ++rm abcdefg
> ++
> ++# how about when escaping pattern characters?
> ++touch '*abc.c'
> ++a='\**.c'
> ++printf '%s\n' $a
> ++rm -f '*abc.c'
> ++
> ++# how about when making the distinction between readable and searchable path
> ++# components?
> ++mkdir -m a=x searchable
> ++mkdir -m a=r readable
> ++
> ++p='searchable/\.'
> ++printf "%s\n" $p
> ++
> ++p='searchable/\./.'
> ++printf "%s\n" $p
> ++
> ++p='readable/\.'
> ++printf "%s\n" $p
> ++
> ++p='readable/\./.'
> ++printf "%s\n" $p
> ++
> ++printf "%s\n" 'searchable/\.'
> ++printf "%s\n" 'readable/\.'
> ++
> ++echo */.
> ++
> ++p='*/\.'
> ++echo $p
> ++
> ++echo */'.'
> ++
> ++rmdir searchable readable
> ++
> ++cd $ORIG
> ++rmdir $GLOBDIR
> +diff --git a/tests/glob7.sub b/tests/glob7.sub
> +new file mode 100644
> +index 0000000..0212b8e
> +--- /dev/null
> ++++ b/tests/glob7.sub
> +@@ -0,0 +1,11 @@
> ++# according to Posix 2.13.3, a slash in a bracket expression renders that
> ++# bracket expression invalid
> ++shopt -s nullglob
> ++
> ++echo 1: [qwe/qwe]
> ++echo 2: [qwe/
> ++echo 3: [qwe/]
> ++
> ++echo 4: [qwe\/qwe]
> ++echo 5: [qwe\/
> ++echo 6: [qwe\/]
> +--
> +1.9.1
> diff --git a/meta/recipes-extended/bash/bash_5.0.bb b/meta/recipes-extended/bash/bash_5.0.bb
> index eadc82279d..1b7058746f 100644
> --- a/meta/recipes-extended/bash/bash_5.0.bb
> +++ b/meta/recipes-extended/bash/bash_5.0.bb
> @@ -19,6 +19,7 @@ SRC_URI = "${GNU_MIRROR}/bash/${BP}.tar.gz;name=tarball \
>              file://run-ptest \
>              file://run-bash-ptests \
>              file://fix-run-builtins.patch \
> +           file://bash-CVE-2019-18276.patch \
>              "
>   
>   SRC_URI[tarball.md5sum] = "2b44b47b905be16f45709648f671820b"
> 



More information about the Openembedded-devel mailing list