From: Chet Ramey Date: Mon, 11 Mar 2019 12:57:46 +0000 (-0400) Subject: commit bash-20190308 snapshot X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=203f479c03ea9ec2023c68ea8f62624a2914bb15;p=thirdparty%2Fbash.git commit bash-20190308 snapshot --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index cefc5ec4f..1e92197c5 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -5459,3 +5459,51 @@ subst.c string (after dequoting) is not null. For instance ${v= ''} should not have the SAWQUOTEDNULL flag set because it is " " after expansion and dequoting, even though we saw a quoted null there + + 3/6 + --- +lib/sh/eaccess.c + - sh_eaccess: AIX needs the same kind of additional checks as FreeBSD + and Solaris when running as root and checking whether or not a file + is executable. Report and fix from REIX, Tony + + 3/7 + --- +lib/glob/glob.h + - GX_RECURSE: new flag, indicates internal call to glob_filename + +lib/glob/glob.c + - glob_filename: add GX_RECURSE to recursive call to glob_filename + - glob_filename: dequote a directory name (in the absence of a + filename) only if this is not a recursive call to glob_filename + ((flags & GX_RECURSE) == 0). Fixes bug reported by Dr. Werner Fink + + + 3/8 + --- +parse.y + - handle_eof_input_unit: before calling exit_builtin, set + last_shell_builtin and this_shell_builtin appropriately, since the + exit builtin uses them to determine whether or not to exit + immediately. Fixes bug reported by Tom Levy + +lib/sh/shquote.c + - sh_double_quote,sh_mkdoublequoted,sh_backslash_quote_for_double_quotes: + make sure to handle multibyte characters that may contain characters + that need to be quoted in double quotes; adding a spurious double + quote may turn them into different characters or uncover characters + that are special in double quotes. Fixes bug reported by + Stephane Chazelas + - sh_backslash_quote: don't call COPY_CHAR_P if we're in a UTF-8 + locale and the current character doesn't have its eighth bit set; + only check mb_cur_max and is_basic if we're not in a UTF-8 character + set + + 3/9 + --- +subst.c + - read_comsub: if it looks like we're starting a multibyte character, + read a whole multibyte character from buf and add it all at once, + so we don't quote each byte in a multibyte character sequence. Fixes + bug uncovered by shquote changes from 3/8 + diff --git a/doc/bash.1 b/doc/bash.1 index 7393c2abb..a25e50dfe 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -5360,6 +5360,9 @@ command under .SM .B "SHELL BUILTIN COMMANDS" below). +This can have unwanted side effects if escaped portions of the string +appear within command substitution or contain characters special to +word expansion. .SH READLINE This is the library that handles reading input when using an interactive shell, unless the diff --git a/doc/bashref.texi b/doc/bashref.texi index 769e6e68c..1d59bf643 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -7490,6 +7490,9 @@ After the string is decoded, it is expanded via parameter expansion, command substitution, arithmetic expansion, and quote removal, subject to the value of the @code{promptvars} shell option (@pxref{The Shopt Builtin}). +This can have unwanted side effects if escaped portions of the string +appear within command substitution or contain characters special to +word expansion. @node The Restricted Shell @section The Restricted Shell diff --git a/lib/glob/glob.c b/lib/glob/glob.c index 51c585cee..50c263da1 100644 --- a/lib/glob/glob.c +++ b/lib/glob/glob.c @@ -1194,7 +1194,7 @@ glob_filename (pathname, flags) if (d[directory_len - 1] == '/') d[directory_len - 1] = '\0'; - directories = glob_filename (d, dflags); + directories = glob_filename (d, dflags|GX_RECURSE); if (free_dirname) { @@ -1351,11 +1351,20 @@ only_filename: free (directory_name); return (NULL); } - if (directory_len > 0 && hasglob == 2) /* need to dequote */ + /* If we have a directory name with quoted characters, and we are + being called recursively to glob the directory portion of a pathname, + we need to dequote the directory name before returning it so the + caller can read the directory */ + if (directory_len > 0 && hasglob == 2 && (flags & GX_RECURSE) != 0) { dequote_pathname (directory_name); directory_len = strlen (directory_name); } + + /* We could check whether or not the dequoted directory_name is a + directory and return it here, returning the original directory_name + if not, but we don't do that yet. I'm not sure it matters. */ + /* Handle GX_MARKDIRS here. */ result[0] = (char *) malloc (directory_len + 1); if (result[0] == NULL) diff --git a/lib/glob/glob.h b/lib/glob/glob.h index b94623336..56ac08ba6 100644 --- a/lib/glob/glob.h +++ b/lib/glob/glob.h @@ -30,6 +30,7 @@ #define GX_NULLDIR 0x100 /* internal -- no directory preceding pattern */ #define GX_ADDCURDIR 0x200 /* internal -- add passed directory name */ #define GX_GLOBSTAR 0x400 /* turn on special handling of ** */ +#define GX_RECURSE 0x800 /* internal -- glob_filename called recursively */ extern int glob_pattern_p __P((const char *)); extern char **glob_vector __P((char *, char *, int)); diff --git a/lib/sh/eaccess.c b/lib/sh/eaccess.c index 3d8ae4e85..0f8ccfef0 100644 --- a/lib/sh/eaccess.c +++ b/lib/sh/eaccess.c @@ -213,10 +213,10 @@ sh_eaccess (path, mode) # else /* HAVE_EACCESS */ /* FreeBSD */ ret = eaccess (path, mode); /* XXX -- not always correct for X_OK */ # endif /* HAVE_EACCESS */ -# if defined (__FreeBSD__) || defined (SOLARIS) +# if defined (__FreeBSD__) || defined (SOLARIS) || defined (_AIX) if (ret == 0 && current_user.euid == 0 && mode == X_OK) return (sh_stataccess (path, mode)); -# endif /* __FreeBSD__ || SOLARIS */ +# endif /* __FreeBSD__ || SOLARIS || _AIX */ return ret; #elif defined (EFF_ONLY_OK) /* SVR4(?), SVR4.2 */ return access (path, mode|EFF_ONLY_OK); diff --git a/lib/sh/shquote.c b/lib/sh/shquote.c index 97e2bc533..1e36e980f 100644 --- a/lib/sh/shquote.c +++ b/lib/sh/shquote.c @@ -1,6 +1,6 @@ /* shquote - functions to quote and dequote strings */ -/* Copyright (C) 1999-2015 Free Software Foundation, Inc. +/* Copyright (C) 1999-2019 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -136,8 +136,15 @@ sh_double_quote (string) const char *string; { register unsigned char c; + int mb_cur_max; char *result, *r; - const char *s; + size_t slen; + const char *s, *send; + DECLARE_MBSTATE; + + slen = strlen (string); + send = string + slen; + mb_cur_max = MB_CUR_MAX; result = (char *)xmalloc (3 + (2 * strlen (string))); r = result; @@ -148,12 +155,19 @@ sh_double_quote (string) /* Backslash-newline disappears within double quotes, so don't add one. */ if ((sh_syntaxtab[c] & CBSDQUOTE) && c != '\n') *r++ = '\\'; -#if 0 - /* Assume that the string will not be further expanded. */ - else if (c == CTLESC || c == CTLNUL) - *r++ = CTLESC; /* could be '\\'? */ + +#if defined (HANDLE_MULTIBYTE) + if ((locale_utf8locale && (c & 0x80)) || + (locale_utf8locale == 0 && mb_cur_max > 1 && is_basic (c) == 0)) + { + COPY_CHAR_P (r, s, send); + s--; /* compensate for auto-increment in loop above */ + continue; + } #endif + /* Assume that the string will not be further expanded, so no need to + add CTLESC to protect CTLESC or CTLNUL. */ *r++ = c; } @@ -171,16 +185,29 @@ sh_mkdoublequoted (s, slen, flags) int slen, flags; { char *r, *ret; - int rlen; + const char *send; + int rlen, mb_cur_max; + DECLARE_MBSTATE; + send = s + slen; + mb_cur_max = flags ? MB_CUR_MAX : 1; rlen = (flags == 0) ? slen + 3 : (2 * slen) + 1; ret = r = (char *)xmalloc (rlen); - + *r++ = '"'; while (*s) { if (flags && *s == '"') *r++ = '\\'; + +#if defined (HANDLE_MULTIBYTE) + if (flags && ((locale_utf8locale && (*s & 0x80)) || + (locale_utf8locale == 0 && mb_cur_max > 1 && is_basic (*s) == 0))) + { + COPY_CHAR_P (r, s, send); + continue; + } +#endif *r++ = *s++; } *r++ = '"'; @@ -259,7 +286,8 @@ sh_backslash_quote (string, table, flags) *r++ = c; continue; } - if (mb_cur_max > 1 && is_basic (c) == 0) + if ((locale_utf8locale && (c & 0x80)) || + (locale_utf8locale == 0 && mb_cur_max > 1 && is_basic (c) == 0)) { COPY_CHAR_P (r, s, send); s--; /* compensate for auto-increment in loop above */ @@ -291,18 +319,35 @@ sh_backslash_quote_for_double_quotes (string) char *string; { unsigned char c; - char *result, *r, *s; - - result = (char *)xmalloc (2 * strlen (string) + 1); + char *result, *r, *s, *send; + size_t slen; + int mb_cur_max; + DECLARE_MBSTATE; + + slen = strlen (string); + send = string + slen; + mb_cur_max = MB_CUR_MAX; + result = (char *)xmalloc (2 * slen + 1); for (r = result, s = string; s && (c = *s); s++) { - if (sh_syntaxtab[c] & CBSDQUOTE) + /* Backslash-newline disappears within double quotes, so don't add one. */ + if ((sh_syntaxtab[c] & CBSDQUOTE) && c != '\n') *r++ = '\\'; - /* I should probably add flags for these to sh_syntaxtab[] */ + /* I should probably use the CSPECL flag for these in sh_syntaxtab[] */ else if (c == CTLESC || c == CTLNUL) *r++ = CTLESC; /* could be '\\'? */ +#if defined (HANDLE_MULTIBYTE) + if ((locale_utf8locale && (c & 0x80)) || + (locale_utf8locale == 0 && mb_cur_max > 1 && is_basic (c) == 0)) + { + COPY_CHAR_P (r, s, send); + s--; /* compensate for auto-increment in loop above */ + continue; + } +#endif + *r++ = c; } diff --git a/parse.y b/parse.y index cb8e50084..68bb078ac 100644 --- a/parse.y +++ b/parse.y @@ -6361,6 +6361,9 @@ handle_eof_input_unit () /* In this case EOF should exit the shell. Do it now. */ reset_parser (); + + last_shell_builtin = this_shell_builtin; + this_shell_builtin = exit_builtin; exit_builtin ((WORD_LIST *)NULL); } else diff --git a/subst.c b/subst.c index 45a05f6d3..13b29edaa 100644 --- a/subst.c +++ b/subst.c @@ -6037,11 +6037,18 @@ read_comsub (fd, quoted, flags, rflag) int fd, quoted, flags; int *rflag; { - char *istring, buf[128], *bufp; + char *istring, buf[512], *bufp; int istring_index, c, tflag, skip_ctlesc, skip_ctlnul; + int mb_cur_max; size_t istring_size; ssize_t bufn; int nullbyte; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; + wchar_t wc; + size_t mblen; + int i; +#endif istring = (char *)NULL; istring_index = istring_size = bufn = tflag = 0; @@ -6049,6 +6056,7 @@ read_comsub (fd, quoted, flags, rflag) skip_ctlesc = ifs_cmap[CTLESC]; skip_ctlnul = ifs_cmap[CTLNUL]; + mb_cur_max = MB_CUR_MAX; nullbyte = 0; /* Read the output of the command through the pipe. This may need to be @@ -6079,7 +6087,7 @@ read_comsub (fd, quoted, flags, rflag) } /* Add the character to ISTRING, possibly after resizing it. */ - RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE); + RESIZE_MALLOCED_BUFFER (istring, istring_index, mb_cur_max+1, istring_size, DEFAULT_ARRAY_SIZE); /* This is essentially quote_string inline */ if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */) @@ -6094,6 +6102,27 @@ read_comsub (fd, quoted, flags, rflag) else if ((skip_ctlnul == 0 && c == CTLNUL) || (c == ' ' && (ifs_value && *ifs_value == 0))) istring[istring_index++] = CTLESC; +#if defined (HANDLE_MULTIBYTE) + if ((locale_utf8locale && (c & 0x80)) || + (locale_utf8locale == 0 && mb_cur_max > 1 && (unsigned char)c > 127)) + { + /* read a multibyte character from buf */ + /* punt on the hard case for now */ + memset (&ps, '\0', sizeof (mbstate_t)); + mblen = mbrtowc (&wc, bufp-1, bufn+1, &ps); + if (MB_INVALIDCH (mblen) || mblen == 0 || mblen == 1) + istring[istring_index++] = c; + else + { + istring[istring_index++] = c; + for (i = 0; i < mblen-1; i++) + istring[istring_index++] = *bufp++; + bufn -= mblen - 1; + } + continue; + } +#endif + istring[istring_index++] = c; #if 0 @@ -10250,9 +10279,7 @@ add_twochars: a special case; it's the only case where a quoted string can expand into more than one word. It's going to come back from the above call to expand_word_internal as a list with - a single word, in which all characters are quoted and - separated by blanks. What we want to do is to turn it back - into a list for the next piece of code. */ + multiple words. */ if (list) dequote_list (list); diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index 58c375b70..554f3d6ec 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -1,4 +1,4 @@ -BUILD_DIR=/usr/local/build/chet/bash/bash-current +BUILD_DIR=/usr/local/build/bash/bash-current THIS_SH=$BUILD_DIR/bash PATH=$PATH:$BUILD_DIR diff --git a/tests/glob.right b/tests/glob.right index 3e3ee55cb..754aa12d0 100644 --- a/tests/glob.right +++ b/tests/glob.right @@ -63,12 +63,31 @@ a? aa -/tmp/a/b/c /tmp/a/b/c /tmp/a/b/c -/tmp/a/b/c /tmp/a/b/c /tmp/a/b/c -/tmp/a/b/c -/tmp/a/b/c -/tmp\/a/b/c -/tm[p]\/a/b/c +./tmp/a/b/c ./tmp/a/b/c ./tmp/a/b/c +./tmp/a/b/c ./tmp/a/b/c ./tmp/a/b/c +./tmp/a/b/c +./tmp/a/b/c +./tmp\/a/b/c +./tm[p]\/a/b/c +./tmp/a/b/c +argv[1] = <./tmp/a/*> +argv[1] = <./tmp/a/*> +argv[1] = <./tmp/a/b/c> +argv[1] = <./tmp/a/*> +argv[1] = <./tmp/a/b/c> +argv[1] = <./t\mp/a/*> +argv[1] = <./tmp/a/b/c> +argv[1] = <./tmp/a/> +argv[1] = <./tmp/a/b/> +argv[1] = <./t\mp/a/> +argv[1] = <./t\mp/a/b/> +argv[1] = <./tmp/a/*> +argv[1] = <./tmp/a/b/c> +argv[1] = <./tmp/a> +argv[1] = <./tmp/a/b*> +argv[1] = <./tmp/a> +argv[1] = <./tmp/a/b*> +argv[1] = <./tmp/> argv[1] = argv[2] = argv[3] = diff --git a/tests/glob5.sub b/tests/glob5.sub index 8075cb3ca..aaa9076d6 100644 --- a/tests/glob5.sub +++ b/tests/glob5.sub @@ -1,16 +1,54 @@ -mkdir -m700 /tmp/a /tmp/a/b -touch /tmp/a/b/c +ORIGD=$PWD +: ${TMPDIR:=/var/tmp} -echo /tmp/a/b/* "/tmp/a/"b/* "/tmp/a/b"/* +SD=$TMPDIR/scratch-$$ +[ -d $SD ] || mkdir $SD +cd $SD +mkdir tmp -chmod -r /tmp/a -echo /tmp/a/b/* "/tmp/a/"b/* "/tmp/a/b"/* -echo "/tmp/a/b"/* +D=./tmp/a +D1='./t\mp/a' + +mkdir -m700 ./tmp/a ./tmp/a/b +touch ./tmp/a/b/c + +echo ./tmp/a/b/* "./tmp/a/"b/* "./tmp/a/b"/* + +chmod -r ./tmp/a +echo ./tmp/a/b/* "./tmp/a/"b/* "./tmp/a/b"/* +echo "./tmp/a/b"/* bs=\\ -echo /tmp${bs}/a/b/* -echo /tmp${bs}/a/b/c -echo /tm[p]${bs}/a/b/c +echo ./tmp${bs}/a/b/* +echo ./tmp${bs}/a/b/c +echo ./tm[p]${bs}/a/b/c +echo ./t${bs}mp/a/b/* + +recho "./tmp/a"/* +recho "$D"/* +recho "$D"/b/* + +recho $D/* +recho $D/b/* +recho $D1/* +recho $D1/b/* +recho $D/ +recho $D/b/ +recho $D1/ +recho $D1/b/ + +recho ./t\mp/a/* +recho ./t\mp/a/b/* + +recho ./tmp/a* +recho ./tmp/a/b* +recho ./t\mp/a* +recho ./t\mp/a/b* + +recho ./t\mp/ + +chmod +r ./tmp/a +rm -rf ./tmp/a -chmod +r /tmp/a -rm -rf /tmp/a +cd $ORIGD +rm -rf $SD