mirror of https://github.com/google/oss-fuzz.git
golang: fix multipart fuzzer (#8816)
Adds an updated version of [this fuzzer](https://github.com/AdamKorcz/go-fuzz-corpus/blob/master/multipart/main.go) that invokes the garbage collector manually. This prevents _some_ incorrect OOM crashes reported by OSS-Fuzz, for example https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=52536 Signed-off-by: AdamKorcz <adam@adalogics.com> Signed-off-by: AdamKorcz <adam@adalogics.com>
This commit is contained in:
parent
8ec85eb8e5
commit
a065702de6
|
@ -42,6 +42,7 @@ COPY build.sh text_fuzzer.go \
|
|||
webp_fuzzer.go \
|
||||
filepath_fuzzer.go \
|
||||
strings_fuzzer.go \
|
||||
multipart_fuzzer.go \
|
||||
glob_fuzzer.options $SRC/
|
||||
|
||||
WORKDIR $SRC/golang
|
||||
|
|
|
@ -45,6 +45,8 @@ function setup_golang_fuzzers() {
|
|||
|
||||
cp $SRC/strings_fuzzer.go $SRC/golang/strings/
|
||||
|
||||
cp $SRC/multipart_fuzzer.go $SRC/golang/multipart/main.go
|
||||
|
||||
go mod init "github.com/dvyukov/go-fuzz-corpus"
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
// Copyright 2015 go-fuzz project authors. All rights reserved.
|
||||
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
||||
|
||||
package multipart
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/textproto"
|
||||
"runtime"
|
||||
|
||||
"github.com/dvyukov/go-fuzz-corpus/fuzz"
|
||||
)
|
||||
|
||||
type Part struct {
|
||||
hdr textproto.MIMEHeader
|
||||
data []byte
|
||||
}
|
||||
|
||||
func Fuzz(data []byte) int {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
}
|
||||
runtime.GC()
|
||||
}()
|
||||
const boundary = "dfhjksd23f43242f43fv4b4g2g2g23vf2"
|
||||
{
|
||||
r := multipart.NewReader(bytes.NewReader(data), boundary)
|
||||
f, err := r.ReadForm(1 << 20)
|
||||
if err == nil {
|
||||
f.RemoveAll()
|
||||
}
|
||||
}
|
||||
fmt.Println("Creating multipart reader")
|
||||
r := multipart.NewReader(bytes.NewReader(data), boundary)
|
||||
fmt.Println("Reading")
|
||||
var parts []Part
|
||||
for {
|
||||
p, err := r.NextPart()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
p.FileName()
|
||||
p.FormName()
|
||||
pdata, err := ioutil.ReadAll(p)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
p.Close()
|
||||
// The parser is loose here.
|
||||
// If data contains \n followed by boundary (but without \r),
|
||||
// it parses it as part body. However, when it serializes it back,
|
||||
// it writes \r\n followed by boundary, which becomes new part separator.
|
||||
if bytes.Contains(pdata, []byte(boundary)) {
|
||||
continue
|
||||
}
|
||||
parts = append(parts, Part{p.Header, pdata})
|
||||
}
|
||||
if len(parts) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
fmt.Println("Creating new writer")
|
||||
buf := new(bytes.Buffer)
|
||||
w := multipart.NewWriter(buf)
|
||||
w.SetBoundary(boundary)
|
||||
fmt.Println("Writing data")
|
||||
for _, p := range parts {
|
||||
pw, err := w.CreatePart(p.hdr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
n, err := pw.Write(p.data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if n != len(p.data) {
|
||||
panic("partial write")
|
||||
}
|
||||
}
|
||||
w.Close()
|
||||
|
||||
fmt.Println("Time to compare")
|
||||
data1 := buf.Bytes()
|
||||
r1 := multipart.NewReader(buf, boundary)
|
||||
var parts1 []Part
|
||||
for {
|
||||
p, err := r1.NextPart()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Printf("parts0: %+v\n", parts)
|
||||
fmt.Printf("data0: %q\n", data)
|
||||
fmt.Printf("data1: %q\n", data1)
|
||||
panic(err)
|
||||
}
|
||||
p.FileName()
|
||||
p.FormName()
|
||||
pdata, err := ioutil.ReadAll(p)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
p.Close()
|
||||
parts1 = append(parts1, Part{p.Header, pdata})
|
||||
}
|
||||
|
||||
fmt.Println("Performing deep equal")
|
||||
|
||||
if !fuzz.DeepEqual(parts, parts1) {
|
||||
fmt.Printf("parts0: %+v\n", parts)
|
||||
fmt.Printf("parts1: %+v\n", parts1)
|
||||
fmt.Printf("data0: %q\n", data)
|
||||
fmt.Printf("data1: %q\n", data1)
|
||||
panic("data has changed")
|
||||
}
|
||||
return 1
|
||||
}
|
Loading…
Reference in New Issue