aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@nbd.name>2017-01-31 21:58:55 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2017-01-31 21:58:55 +0100
commitb5b21126ca9217e1f721996cbef44c019185dd5d (patch)
tree1c8e640b4ea471ab7949863a9f07771a77a59e61
parentd6ace669737571c98977972b7392456f9e5156f6 (diff)
downloadbusybox-w32-b5b21126ca9217e1f721996cbef44c019185dd5d.tar.gz
busybox-w32-b5b21126ca9217e1f721996cbef44c019185dd5d.tar.bz2
busybox-w32-b5b21126ca9217e1f721996cbef44c019185dd5d.zip
ash: improve / fix glob expansion
When using musl libc glob() a very long string can cause glob() to fail, which leads to an out of memory error being raised by ash. This can happen easily if a very long quoted string contains *, even though no glob expansion should ever be performed on it (since it's quoted). Fix this by properly parsing control characters and escaping and only accept unquoted metacharacters. While we're at it, unify this check for libc and built-in glob expansion Signed-off-by: Felix Fietkau <nbd@nbd.name> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/ash.c71
1 files changed, 54 insertions, 17 deletions
diff --git a/shell/ash.c b/shell/ash.c
index e07b81c05..6be3ec600 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -7160,6 +7160,57 @@ addfname(const char *name)
7160 exparg.lastp = &sp->next; 7160 exparg.lastp = &sp->next;
7161} 7161}
7162 7162
7163/* Avoid glob() (and thus, stat() et al) for words like "echo" */
7164static int
7165hasmeta(const char *p)
7166{
7167 static const char chars[] ALIGN1 = {
7168 '*', '?', '[', '\\', CTLQUOTEMARK, CTLESC, 0
7169 };
7170
7171 for (;;) {
7172 p = strpbrk(p, chars);
7173 if (!p)
7174 break;
7175 switch ((unsigned char) *p) {
7176 case CTLQUOTEMARK:
7177 for (;;) {
7178 p++;
7179 if (*p == CTLQUOTEMARK)
7180 break;
7181 if (*p == CTLESC)
7182 p++;
7183 if (*p == '\0') /* huh? */
7184 return 0;
7185 }
7186 break;
7187 case '\\':
7188 case CTLESC:
7189 p++;
7190 if (*p == '\0')
7191 return 0;
7192 break;
7193 case '[':
7194 if (!strchr(p + 1, ']')) {
7195 /* It's not a properly closed [] pattern,
7196 * but other metas may follow. Continue checking.
7197 * my[file* _is_ globbed by bash
7198 * and matches filenames like "my[file1".
7199 */
7200 break;
7201 }
7202 /* fallthrough */
7203 default:
7204 /* case '*': */
7205 /* case '?': */
7206 return 1;
7207 }
7208 p++;
7209 }
7210
7211 return 0;
7212}
7213
7163/* If we want to use glob() from libc... */ 7214/* If we want to use glob() from libc... */
7164#if !ENABLE_ASH_INTERNAL_GLOB 7215#if !ENABLE_ASH_INTERNAL_GLOB
7165 7216
@@ -7186,20 +7237,9 @@ expandmeta(struct strlist *str /*, int flag*/)
7186 if (fflag) 7237 if (fflag)
7187 goto nometa; 7238 goto nometa;
7188 7239
7189 /* Avoid glob() (and thus, stat() et al) for words like "echo" */ 7240 if (!hasmeta(str->text))
7190 p = str->text; 7241 goto nometa;
7191 while (*p) {
7192 if (*p == '*')
7193 goto need_glob;
7194 if (*p == '?')
7195 goto need_glob;
7196 if (*p == '[')
7197 goto need_glob;
7198 p++;
7199 }
7200 goto nometa;
7201 7242
7202 need_glob:
7203 INT_OFF; 7243 INT_OFF;
7204 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); 7244 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7205// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match 7245// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
@@ -7436,9 +7476,6 @@ expsort(struct strlist *str)
7436static void 7476static void
7437expandmeta(struct strlist *str /*, int flag*/) 7477expandmeta(struct strlist *str /*, int flag*/)
7438{ 7478{
7439 static const char metachars[] ALIGN1 = {
7440 '*', '?', '[', 0
7441 };
7442 /* TODO - EXP_REDIR */ 7479 /* TODO - EXP_REDIR */
7443 7480
7444 while (str) { 7481 while (str) {
@@ -7449,7 +7486,7 @@ expandmeta(struct strlist *str /*, int flag*/)
7449 7486
7450 if (fflag) 7487 if (fflag)
7451 goto nometa; 7488 goto nometa;
7452 if (!strpbrk(str->text, metachars)) 7489 if (!hasmeta(str->text))
7453 goto nometa; 7490 goto nometa;
7454 savelastp = exparg.lastp; 7491 savelastp = exparg.lastp;
7455 7492