From f3379f650a3de0e83903e3aa34d39b4ec647ee50 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Sun, 26 Feb 2023 16:56:48 -0500 Subject: caddyfile: Fix heredoc fuzz crasher, drop trailing newline (#5404) Co-authored-by: Mohammed Al Sahaf --- caddyconfig/caddyfile/lexer.go | 19 +++++++--- caddyconfig/caddyfile/lexer_test.go | 73 ++++++++++++++++++++++++++++++++----- 2 files changed, 76 insertions(+), 16 deletions(-) (limited to 'caddyconfig') diff --git a/caddyconfig/caddyfile/lexer.go b/caddyconfig/caddyfile/lexer.go index ba8b879..1f531f4 100644 --- a/caddyconfig/caddyfile/lexer.go +++ b/caddyconfig/caddyfile/lexer.go @@ -284,15 +284,17 @@ func (l *lexer) next() (bool, error) { // and processes the text to strip leading whitespace, returning the final // value without the leading whitespace. func (l *lexer) finalizeHeredoc(val []rune, marker string) ([]rune, error) { + stringVal := string(val) + // find the last newline of the heredoc, which is where the contents end - lastNewline := strings.LastIndex(string(val), "\n") + lastNewline := strings.LastIndex(stringVal, "\n") // collapse the content, then split into separate lines - lines := strings.Split(string(val[:lastNewline+1]), "\n") + lines := strings.Split(stringVal[:lastNewline+1], "\n") // figure out how much whitespace we need to strip from the front of every line // by getting the string that precedes the marker, on the last line - paddingToStrip := string(val[lastNewline+1 : len(val)-len(marker)]) + paddingToStrip := stringVal[lastNewline+1 : len(stringVal)-len(marker)] // iterate over each line and strip the whitespace from the front var out string @@ -310,6 +312,11 @@ func (l *lexer) finalizeHeredoc(val []rune, marker string) ([]rune, error) { out += strings.ReplaceAll(lineText[len(paddingToStrip):]+"\n", "\r", "") } + // Remove the trailing newline from the loop + if len(out) > 0 && out[len(out)-1] == '\n' { + out = out[:len(out)-1] + } + // return the final value return []rune(out), nil } @@ -340,9 +347,9 @@ func (t Token) NumLineBreaks() int { lineBreaks := strings.Count(t.Text, "\n") if t.wasQuoted == '<' { // heredocs have an extra linebreak because the opening - // delimiter is on its own line and is not included in - // the token Text itself - lineBreaks++ + // delimiter is on its own line and is not included in the + // token Text itself, and the trailing newline is removed. + lineBreaks += 2 } return lineBreaks } diff --git a/caddyconfig/caddyfile/lexer_test.go b/caddyconfig/caddyfile/lexer_test.go index 3c7e157..801d81e 100644 --- a/caddyconfig/caddyfile/lexer_test.go +++ b/caddyconfig/caddyfile/lexer_test.go @@ -256,7 +256,7 @@ EOF same-line-arg `), expected: []Token{ {Line: 1, Text: `heredoc`}, - {Line: 1, Text: "content\n"}, + {Line: 1, Text: "content"}, {Line: 3, Text: `same-line-arg`}, }, }, @@ -267,18 +267,40 @@ VERY-LONG-MARKER same-line-arg `), expected: []Token{ {Line: 1, Text: `heredoc`}, - {Line: 1, Text: "content\n"}, + {Line: 1, Text: "content"}, {Line: 3, Text: `same-line-arg`}, }, }, { input: []byte(`heredoc <