diff --git a/go.mod b/go.mod index 5a6465a07..96374da10 100644 --- a/go.mod +++ b/go.mod @@ -143,4 +143,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/AdaLogics/go-fuzz-headers => github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230111232327-1f10f66a31bf +replace github.com/AdaLogics/go-fuzz-headers => github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230201144411-22e92b796899 diff --git a/go.sum b/go.sum index dc3d2ca4d..6d8772def 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,8 @@ contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0Wk dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= -github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230111232327-1f10f66a31bf h1:EamsQRRH14elXDAofrOK5Ja6fDTJSrbKstpr1grrGX4= -github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230111232327-1f10f66a31bf/go.mod h1:0vOOKsOMKPThRu9lQMAxcQ8D60f8U+wHXl07SyUw0+U= +github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230201144411-22e92b796899 h1:tkR1HRX5M+lhVP9WOioyxEYDyXeV0I2oBAOugCW87xY= +github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230201144411-22e92b796899/go.mod h1:0vOOKsOMKPThRu9lQMAxcQ8D60f8U+wHXl07SyUw0+U= github.com/Azure/azure-amqp-common-go/v3 v3.2.1/go.mod h1:O6X1iYHP7s2x7NjUKsXVhkwWrQhxrd+d8/3rRadj4CI= github.com/Azure/azure-amqp-common-go/v3 v3.2.2/go.mod h1:O6X1iYHP7s2x7NjUKsXVhkwWrQhxrd+d8/3rRadj4CI= github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= diff --git a/pkg/types/alpine/fuzz_test.go b/pkg/types/alpine/fuzz_test.go index 326ae9022..b211b3830 100644 --- a/pkg/types/alpine/fuzz_test.go +++ b/pkg/types/alpine/fuzz_test.go @@ -17,9 +17,9 @@ package alpine import ( "archive/tar" + "bytes" "compress/gzip" - "io" "strings" "testing" @@ -98,180 +98,121 @@ func createPkgInfoFileContents(ff *fuzz.ConsumeFuzzer) ([]byte, error) { return []byte(b.String()), nil } -// Copies files from structured tarBytes to the tw -// This is used when adding files to tarBytes -func copyTarFiles(tw *tar.Writer, tarBytes []byte) error { - tr := tar.NewReader(bytes.NewReader(tarBytes)) - for { - hdr, err := tr.Next() - if err == io.EOF { - break - } - if err != nil { - return err - } - fileContents, err := io.ReadAll(tr) - if err != nil { - return err - } - tw.WriteHeader(hdr) - tw.Write(fileContents) - } - return nil -} - // Adds a .SIGN file to tarBytes -func addSignFile(tw *tar.Writer, ff *fuzz.ConsumeFuzzer, tarBytes []byte) error { - err := copyTarFiles(tw, tarBytes) - if err != nil { - return err - } +func addSignFile(ff *fuzz.ConsumeFuzzer, tarFiles []*fuzz.TarFile) ([]*fuzz.TarFile, error) { SIGNFileContents, err := ff.GetBytes() if err != nil { - return err + return tarFiles, err } + SIGNFileName, err := getSignFilename(ff) if err != nil { - return err + return tarFiles, err } - tw.WriteHeader(&tar.Header{ - Name: SIGNFileName, - Mode: 0644, - Size: int64(len(SIGNFileContents)), - Typeflag: tar.TypeReg, - Gid: 0, - Uid: 0, - }) - tw.Write(SIGNFileContents) - return nil + signFile := &fuzz.TarFile{ + Body: SIGNFileContents, + Hdr: &tar.Header{ + Name: SIGNFileName, + Mode: 0644, + Size: int64(len(SIGNFileContents)), + Typeflag: tar.TypeReg, + Gid: 0, + Uid: 0, + }, + } + tarFiles = append(tarFiles, signFile) + + return tarFiles, nil } // Allows the fuzzer to randomize whether a .SIGN file should // be added to tarBytes -func shouldAddSignFile(ff *fuzz.ConsumeFuzzer, tarBytes []byte) bool { +func shouldAddSignFile(ff *fuzz.ConsumeFuzzer, tarFiles []*fuzz.TarFile) bool { shouldRequireSIGNFile, err := ff.GetBool() if err != nil { return false } if shouldRequireSIGNFile { - tr := tar.NewReader(bytes.NewReader(tarBytes)) - for { - hdr, err := tr.Next() - if err == io.EOF { - return false - } - if err != nil { + for _, tarFile := range tarFiles { + if strings.HasPrefix(tarFile.Hdr.Name, ".SIGN") { return false } - if strings.HasPrefix(hdr.Name, ".SIGN") { - return true - } } + return true } return false } // Allows the fuzzer to randomize whether a .PKGINFO file should // be added to tarBytes -func shouldAddPkgInfoFile(ff *fuzz.ConsumeFuzzer, tarBytes []byte) bool { +func shouldAddPkgInfoFile(ff *fuzz.ConsumeFuzzer, tarFiles []*fuzz.TarFile) bool { shouldRequirePKGINFOFile, err := ff.GetBool() if err != nil { return false } if shouldRequirePKGINFOFile { - tr := tar.NewReader(bytes.NewReader(tarBytes)) - for { - hdr, err := tr.Next() - if err == io.EOF { - return false - } - if err != nil { + for _, tarFile := range tarFiles { + if strings.HasPrefix(tarFile.Hdr.Name, ".PKGINFO") { return false } - if hdr.Name == ".PKGINFO" { - return true - } } + return true } return false } -// Adds the .PKGINFO file to tarBytes -func addPkgInfoFile(tw *tar.Writer, ff *fuzz.ConsumeFuzzer, tarBytes []byte) error { - tr := tar.NewReader(bytes.NewReader(tarBytes)) - for { - hdr, err := tr.Next() - if err == io.EOF { - break - } - if err != nil { - return err - } - fileContents, err := io.ReadAll(tr) - if err != nil { - return err - } - tw.WriteHeader(hdr) - tw.Write(fileContents) - } - PKGINFOFileContents, err := createPkgInfoFileContents(ff) //nolint:all +// Adds the .PKGINFO file to the tar files +func addPkgInfoFile(ff *fuzz.ConsumeFuzzer, tarFiles []*fuzz.TarFile) ([]*fuzz.TarFile, error) { + tarFile := &fuzz.TarFile{} + PKGINFOFileContents, err := createPkgInfoFileContents(ff) if err != nil { - return err + return tarFiles, err } - tw.WriteHeader(&tar.Header{ + tarFile.Body = PKGINFOFileContents + tarFile.Hdr = &tar.Header{ Name: ".PKGINFO", Mode: 0644, Size: int64(len(PKGINFOFileContents)), Typeflag: tar.TypeReg, Gid: 0, Uid: 0, - }) - tw.Write(PKGINFOFileContents) - return nil + } + + return tarFiles, nil } // FuzzPackageUnmarshal implements the fuzz test func FuzzPackageUnmarshal(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { + var tarFiles, tarFiles2 []*fuzz.TarFile + var err error + ff := fuzz.NewConsumer(data) - // signature segment - tarBytes, err := ff.TarBytes() + tarFiles, err = ff.TarFiles() if err != nil { return } - - if shouldAddSignFile(ff, tarBytes) { - var buf bytes.Buffer - tw := tar.NewWriter(&buf) - err := addSignFile(tw, ff, tarBytes) + if shouldAddSignFile(ff, tarFiles) { + tarFiles, err = addSignFile(ff, tarFiles) if err != nil { - tw.Close() t.Skip() } - tw.Close() - tarBytes = buf.Bytes() } - // control segment - tarBytes2, err := ff.TarBytes() + tarFiles2, err = ff.TarFiles() if err != nil { t.Skip() } - if shouldAddPkgInfoFile(ff, tarBytes2) { - var buf bytes.Buffer - tw := tar.NewWriter(&buf) - err := addPkgInfoFile(tw, ff, tarBytes) + if shouldAddPkgInfoFile(ff, tarFiles2) { + tarFiles2, err = addPkgInfoFile(ff, tarFiles2) if err != nil { - tw.Close() t.Skip() } - tw.Close() - tarBytes2 = buf.Bytes() } - concatenated, err := concatenateTarBytes(tarBytes, tarBytes2) + concatenated, err := concatenateTarArchives(tarFiles, tarFiles2) if err != nil { t.Skip() } @@ -281,8 +222,25 @@ func FuzzPackageUnmarshal(f *testing.F) { }) } -// Concatenates two tar archives. -func concatenateTarBytes(tarBytes []byte, tarBytes2 []byte) ([]byte, error) { +func concatenateTarArchives(tarFiles1 []*fuzz.TarFile, tarFiles2 []*fuzz.TarFile) ([]byte, error) { + var buf1, buf2 bytes.Buffer + + tw1 := tar.NewWriter(&buf1) + for _, tf := range tarFiles1 { + tw1.WriteHeader(tf.Hdr) + tw1.Write(tf.Body) + } + tw1.Close() + tarBytes := buf1.Bytes() + + tw2 := tar.NewWriter(&buf2) + for _, tf := range tarFiles2 { + tw2.WriteHeader(tf.Hdr) + tw2.Write(tf.Body) + } + tw2.Close() + tarBytes2 := buf2.Bytes() + var b1 bytes.Buffer w1 := gzip.NewWriter(&b1) defer w1.Close() diff --git a/tests/fuzz-testdata/FuzzPackageUnmarshal.options b/tests/fuzz-testdata/FuzzPackageUnmarshal.options new file mode 100644 index 000000000..c7fb5a73c --- /dev/null +++ b/tests/fuzz-testdata/FuzzPackageUnmarshal.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 300000 +len_control = 0