upstream commit

revision 1.47
date: 2017/05/08 14:53:27;  author: millert;  state: Exp;  lines: +34 -21;  commitid: sYfxfyUHAfarP8sE;
Fix exponential CPU use with repeated '*' operators by changing '*'
handling to be interative instead of recursive.
Fix by Yves Orton, ported to OpenBSD glob.c by Ray Lai.  OK tb@
This commit is contained in:
Damien Miller 2019-11-15 16:05:07 +11:00
parent 228dd595c7
commit 2cfb11abac
1 changed files with 34 additions and 21 deletions
openbsd-compat

View File

@ -1,4 +1,4 @@
/* $OpenBSD: glob.c,v 1.46 2015/12/28 22:08:18 mmcc Exp $ */ /* $OpenBSD: glob.c,v 1.47 2017/05/08 14:53:27 millert Exp $ */
/* /*
* Copyright (c) 1989, 1993 * Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@ -137,9 +137,6 @@ typedef char Char;
#define GLOB_LIMIT_STAT 2048 #define GLOB_LIMIT_STAT 2048
#define GLOB_LIMIT_READDIR 16384 #define GLOB_LIMIT_READDIR 16384
/* Limit of recursion during matching attempts. */
#define GLOB_LIMIT_RECUR 64
struct glob_lim { struct glob_lim {
size_t glim_malloc; size_t glim_malloc;
size_t glim_stat; size_t glim_stat;
@ -172,7 +169,7 @@ static const Char *
static int globexp1(const Char *, glob_t *, struct glob_lim *); static int globexp1(const Char *, glob_t *, struct glob_lim *);
static int globexp2(const Char *, const Char *, glob_t *, static int globexp2(const Char *, const Char *, glob_t *,
struct glob_lim *); struct glob_lim *);
static int match(Char *, Char *, Char *, int); static int match(Char *, Char *, Char *);
#ifdef DEBUG #ifdef DEBUG
static void qprintf(const char *, Char *); static void qprintf(const char *, Char *);
#endif #endif
@ -763,7 +760,7 @@ glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
break; break;
} }
if (!match(pathend, pattern, restpattern, GLOB_LIMIT_RECUR)) { if (!match(pathend, pattern, restpattern)) {
*pathend = EOS; *pathend = EOS;
continue; continue;
} }
@ -893,17 +890,24 @@ globextend(const Char *path, glob_t *pglob, struct glob_lim *limitp,
/* /*
* pattern matching function for filenames. Each occurrence of the * * pattern matching function for filenames. Each occurrence of the *
* pattern causes a recursion level. * pattern causes an iteration.
*
* Note, this function differs from the original as per the discussion
* here: https://research.swtch.com/glob
*
* Basically we removed the recursion and made it use the algorithm
* from Russ Cox to not go quadratic on cases like a file called
* ("a" x 100) . "x" matched against a pattern like "a*a*a*a*a*a*a*y".
*/ */
static int static int
match(Char *name, Char *pat, Char *patend, int recur) match(Char *name, Char *pat, Char *patend)
{ {
int ok, negate_range; int ok, negate_range;
Char c, k; Char c, k;
Char *nextp = NULL;
Char *nextn = NULL;
if (recur-- == 0) loop:
return(GLOB_NOSPACE);
while (pat < patend) { while (pat < patend) {
c = *pat++; c = *pat++;
switch (c & M_MASK) { switch (c & M_MASK) {
@ -912,19 +916,19 @@ match(Char *name, Char *pat, Char *patend, int recur)
pat++; /* eat consecutive '*' */ pat++; /* eat consecutive '*' */
if (pat == patend) if (pat == patend)
return(1); return(1);
do { if (*name == EOS)
if (match(name, pat, patend, recur)) return(0);
return(1); nextn = name + 1;
} while (*name++ != EOS); nextp = pat - 1;
return(0); break;
case M_ONE: case M_ONE:
if (*name++ == EOS) if (*name++ == EOS)
return(0); goto fail;
break; break;
case M_SET: case M_SET:
ok = 0; ok = 0;
if ((k = *name++) == EOS) if ((k = *name++) == EOS)
return(0); goto fail;
if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
++pat; ++pat;
while (((c = *pat++) & M_MASK) != M_END) { while (((c = *pat++) & M_MASK) != M_END) {
@ -943,15 +947,24 @@ match(Char *name, Char *pat, Char *patend, int recur)
ok = 1; ok = 1;
} }
if (ok == negate_range) if (ok == negate_range)
return(0); goto fail;
break; break;
default: default:
if (*name++ != c) if (*name++ != c)
return(0); goto fail;
break; break;
} }
} }
return(*name == EOS); if (*name == EOS)
return(1);
fail:
if (nextn) {
pat = nextp;
name = nextn;
goto loop;
}
return(0);
} }
/* Free allocated data belonging to a glob_t structure. */ /* Free allocated data belonging to a glob_t structure. */