diff --git a/caddyfile/parse.go b/caddyfile/parse.go index 142a87f93..d8252ff12 100644 --- a/caddyfile/parse.go +++ b/caddyfile/parse.go @@ -263,14 +263,19 @@ func (p *parser) doImport() error { } else { globPattern = importPattern } + if strings.Count(globPattern, "*") > 1 || strings.Count(globPattern, "?") > 1 || + (strings.Contains(globPattern, "[") && strings.Contains(globPattern, "]")) { + // See issue #2096 - a pattern with many glob expansions can hang for too long + return p.Errf("Glob pattern may only contain one wildcard (*), but has others: %s", globPattern) + } matches, err = filepath.Glob(globPattern) if err != nil { return p.Errf("Failed to use import pattern %s: %v", importPattern, err) } if len(matches) == 0 { - if strings.Contains(globPattern, "*") { - log.Printf("[WARNING] No files matching import pattern: %s", importPattern) + if strings.ContainsAny(globPattern, "*?[]") { + log.Printf("[WARNING] No files matching import glob pattern: %s", importPattern) } else { return p.Errf("File to import not found: %s", importPattern) } @@ -440,7 +445,7 @@ func replaceEnvReferences(s, refStart, refEnd string) string { index := strings.Index(s, refStart) for index != -1 { endIndex := strings.Index(s, refEnd) - if endIndex != -1 { + if endIndex > index+len(refStart) { ref := s[index : endIndex+len(refEnd)] s = strings.Replace(s, ref, os.Getenv(ref[len(refStart):len(ref)-len(refEnd)]), -1) } else { diff --git a/caddyfile/parse_test.go b/caddyfile/parse_test.go index f119f7c01..72994ced4 100644 --- a/caddyfile/parse_test.go +++ b/caddyfile/parse_test.go @@ -228,6 +228,17 @@ func TestParseOneAndImport(t *testing.T) { {`""`, false, []string{}, map[string]int{}}, {``, false, []string{}, map[string]int{}}, + + // test cases found by fuzzing! + {`import }{$"`, true, []string{}, map[string]int{}}, + {`import /*/*.txt`, true, []string{}, map[string]int{}}, + {`import /???/?*?o`, true, []string{}, map[string]int{}}, + {`import /??`, true, []string{}, map[string]int{}}, + {`import /[a-z]`, true, []string{}, map[string]int{}}, + {`import {$}`, true, []string{}, map[string]int{}}, + {`import {%}`, true, []string{}, map[string]int{}}, + {`import {$$}`, true, []string{}, map[string]int{}}, + {`import {%%}`, true, []string{}, map[string]int{}}, } { result, err := testParseOne(test.input)