From 64c18a7c6c8c3c179748486bbd06a93f15aa580c Mon Sep 17 00:00:00 2001 From: Matt Holt Date: Tue, 3 Apr 2018 11:54:32 -0600 Subject: [PATCH] caddyfile: Fix errors caught by fuzzing (#2097) * caddyfile: More robust parsing for 'import' (fixes #2096) The fix for hanging involves limiting the number of wildcards in an import pattern to just 1. Otherwise some patterns can expand to the entire disk. The other fix requires that the end string for an environment variable expansion come after the start string. * caddyfile: Fix more fuzzing errors --- caddyfile/parse.go | 11 ++++++++--- caddyfile/parse_test.go | 11 +++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/caddyfile/parse.go b/caddyfile/parse.go index 142a87f9..d8252ff1 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 f119f7c0..72994ced 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)