CVE-2019-18276 (C, published 2019-11-28T01:15Z)
Description: value: 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.
Severity: HIGH (CVSS v3 base score: 7.8)
Weakness: CWE-273 \u2014 Improper Check for Dropped Privileges
The product attempts to drop privileges but does not check or incorrectly checks to see if the drop succeeded.
Repository: https://github.com/bminor/bash
Files changed:
CWRU/CWRU.chlog
MANIFEST
bashline.c
builtins/help.def
config.h.in
configure
configure.ac
doc/bash.1
doc/bashref.texi
lib/glob/glob.c
pathexp.c
shell.c
tests/glob.tests
tests/glob6.sub
tests/glob7.sub
Commit message: commit bash-20190628 snapshot


Vulnerable code:
  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);
  if (glob_pattern_p (list->word->word))
/* Copyright (C) 1987-2009,2011-2012 Free Software Foundation, Inc.
# From configure.ac for Bash 5.0, version 5.010.
AC_REVISION([for Bash 5.0, version 5.010])dnl
expansions, assignments, and redirections, from left to right.
expansions, assignments, and redirections, from left to right.
  if (skip == 0 && glob_pattern_p (pat) == 0)
/* Return nonzero if STRING has any unquoted special globbing chars in it.  */
	  if (open)

Fixed code:

				   6/27
				   ----
{config.h.in,configure.ac}
	- setresuid,setresgid: check and set HAVE_{DECL,}_SETRES[UG]ID as
	  appropriate

shell.c
	- disable_priv_mode: if we have setres[ug]id, use them over
	  set[ug]id, which only set the save user-id and group-id if the
	  process is running as root. From Ian Eldred Pudney
	  in https://savannah.gnu.org/patch/?9822

				   6/28
				   ----
lib/glob/glob.c
	- glob_vector: don't bother trying to read the directory if the filename
	  pattern doesn't have any globbing characters except backslash; just
	  dequote the pattern and try to lstat(2) it as if there were no
	  globbing characters at all. From an austingroup-bugs discussion
	  message from Stephane Chazelas <stephane.chazelas@gmail.com>

bashline.c
	- completion_glob_pattern: just call glob_pattern_p and make sure it
	  returns 1 (non-backslash globbing characters)

builtins/help.def
	- help_builtin: don't try pattern matching the help topic argument
	  unless glob_pattern_p returns 1

pathexp.c
	- unquoted_glob_pattern_p: when in a bracket expression (open > 0),
	  don't allow an unquoted slash as part of the bracket expression.
	  Report from Stephane Chazelas <stephane.chazelas@gmail.com>
tests/glob6.sub		f
tests/glob7.sub		f
  return (glob_pattern_p (string) == 1);
  if (glob_pattern_p (list->word->word) == 1)
/* Copyright (C) 1987-2009,2011-2012,2013-2019 Free Software Foundation, Inc.
/* 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

# From configure.ac for Bash 5.0, version 5.011.
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_REVISION([for Bash 5.0, version 5.011])dnl
AC_CHECK_DECLS[(setresuid, setresgid])
expansions, assignments, and redirections, from left to right, in
the following order.
expansions, assignments, and redirections, from left to right, in
the following order.
  int hasglob;		/* return value from glob_pattern_p */
     or contains a pattern with only backslash escapes (hasglob == 2),
  hasglob = 0;
  if (skip == 0 && (hasglob = glob_pattern_p (pat)) == 0 || hasglob == 2)
/* 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. */
	  if (open)		/* XXX - if --open == 0? */
	case '/':
	  if (open)
	    open = 0;

	  else if (open && *string == '/')
	    {
	      string++;		/* quoted slashes in bracket expressions are ok */
	      continue;
	    }
#if HAVE_DECL_SETRESUID
  if (setresuid (current_user.uid, current_user.uid, current_user.uid) < 0)
#else
#endif
#if HAVE_DECL_SETRESGID
  if (setresgid (current_user.gid, current_user.gid, current_user.gid) < 0)
#else
#endif
${THIS_SH} ./glob6.sub
${THIS_SH} ./glob7.sub
# 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
# 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\/]