mvdan / sh

A shell parser, formatter, and interpreter with bash support; includes shfmt
https://pkg.go.dev/mvdan.cc/sh/v3
BSD 3-Clause "New" or "Revised" License
7.35k stars 348 forks source link

Panic in parser found by fuzzing #1098

Closed Cravtos closed 2 months ago

Cravtos commented 2 months ago

Version: 3.9.0

Fuzzing test:

func FuzzParser(f *testing.F) {
    f.Fuzz(func(t *testing.T, script []byte) {
        _, _ = syntax.NewParser().Parse(bytes.NewReader(script), "")
    })
}

Input: input.txt

Stacktrace:

panic: runtime error: slice bounds out of range [:-1] [recovered]
    panic: runtime error: slice bounds out of range [:-1]

goroutine 5 [running]:
testing.tRunner.func1.2({0x101378660, 0x14000572168})
    /Users/user/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.5.darwin-arm64/src/testing/testing.go:1631 +0x1c4
testing.tRunner.func1()
    /Users/user/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.5.darwin-arm64/src/testing/testing.go:1634 +0x33c
panic({0x101378660?, 0x14000572168?})
    /Users/user/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.5.darwin-arm64/src/runtime/panic.go:770 +0x124
mvdan.cc/sh/v3/syntax.(*Parser).endLit(...)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/lexer.go:827
mvdan.cc/sh/v3/syntax.(*Parser).advanceNameCont(0x140001f8a88, 0x5c)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/lexer.go:862 +0x178
mvdan.cc/sh/v3/syntax.(*Parser).wordPart(0x140001f8a88)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:1064 +0x1c4
mvdan.cc/sh/v3/syntax.(*Parser).wordParts(0x140001f8a88, {0x140002da4b8?, 0x0?, 0x8?})
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:961 +0x40
mvdan.cc/sh/v3/syntax.(*Parser).wordAnyNumber(0x0?)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:475 +0xd8
mvdan.cc/sh/v3/syntax.(*Parser).getWord(...)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:943
mvdan.cc/sh/v3/syntax.(*Parser).doHeredocs(0x140001f8a88)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:613 +0x248
mvdan.cc/sh/v3/syntax.(*Parser).next(0x140001f8a88)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/lexer.go:248 +0x3e8
mvdan.cc/sh/v3/syntax.(*Parser).getLit(0x140001f8a88)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:953 +0x4c
mvdan.cc/sh/v3/syntax.(*Parser).declClause(0x140001f8a88, 0x1400068e240)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:2266 +0x26c
mvdan.cc/sh/v3/syntax.(*Parser).gotStmtPipe(0x140001f8a88, 0x1400068e240, 0x0)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:1753 +0x848
mvdan.cc/sh/v3/syntax.(*Parser).getStmt(0x140001f8a88, 0x1, 0x0, 0x0)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:1646 +0x154
mvdan.cc/sh/v3/syntax.(*Parser).stmts(0x140001f8a88, 0x1400004cc38, {0x1400004cc98, 0x1, 0x14000576240?})
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:883 +0x1d8
mvdan.cc/sh/v3/syntax.(*Parser).stmtList(0x140001f8a88, {0x14000110c98?, 0x14000110d48?, 0x1010f4a44?})
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:903 +0x54
mvdan.cc/sh/v3/syntax.(*Parser).block(0x140001f8a88, 0x14000570ea0)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:1879 +0x6c
mvdan.cc/sh/v3/syntax.(*Parser).gotStmtPipe(0x140001f8a88, 0x14000570ea0, 0x0)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:1703 +0x174
mvdan.cc/sh/v3/syntax.(*Parser).getStmt(0x140001f8a88, 0x0, 0x1, 0x0)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:1646 +0x154
mvdan.cc/sh/v3/syntax.(*Parser).getStmt(0x140001f8a88, 0x1, 0x0, 0x0)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:1663 +0x22c
mvdan.cc/sh/v3/syntax.(*Parser).stmts(0x140001f8a88, 0x1400004cfd8, {0x0, 0x0, 0x1400042e0f0?})
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:883 +0x1d8
mvdan.cc/sh/v3/syntax.(*Parser).stmtList(0x140001f8a88, {0x0?, 0x14000584a00?, 0x14e7?})
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:903 +0x54
mvdan.cc/sh/v3/syntax.(*Parser).wordPart(0x140001f8a88)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:1135 +0x3d0
mvdan.cc/sh/v3/syntax.(*Parser).wordParts(0x140001f8a88, {0x140002d96e8?, 0x50?, 0x10131a7c0?})
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:961 +0x40
mvdan.cc/sh/v3/syntax.(*Parser).wordAnyNumber(0x14e7?)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:475 +0xd8
mvdan.cc/sh/v3/syntax.(*Parser).callExpr(0x140001f8a88, 0x14000570360, 0x140002d96a8, 0x0)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:2408 +0x280
mvdan.cc/sh/v3/syntax.(*Parser).gotStmtPipe(0x140001f8a88, 0x14000570360, 0x0)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:1787 +0x9e4
mvdan.cc/sh/v3/syntax.(*Parser).getStmt(0x140001f8a88, 0x1, 0x0, 0x0)
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:1646 +0x154
mvdan.cc/sh/v3/syntax.(*Parser).stmts(0x140001f8a88, 0x1400004d5b8, {0x0, 0x0, 0x140005761c0?})
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:883 +0x1d8
mvdan.cc/sh/v3/syntax.(*Parser).stmtList(0x140001f8a88, {0x0?, 0x1?, 0x10138cf40?})
    /Users/.../vendor/mvdan.cc/sh/v3/syntax/parser.go:903 +0x54
mvdan.cc/sh/v3/syntax.(*Parser).Parse(0x140001f8a88, {0x1013bc338, 0x140005ce3f0}, {0x0, 0x0})
mvdan commented 2 months ago

Thank you - we already have a fuzzer on master and it found this crash very quickly. I guess I just haven't been fuzzing as often as I should lately.