diff --git a/fuzz_test.go b/fuzz_test.go new file mode 100644 index 0000000..0a6d0dd --- /dev/null +++ b/fuzz_test.go @@ -0,0 +1,50 @@ +//go:build go1.18 +// +build go1.18 + +// Fuzzing test(s) are gated behind build tags in order to avoid generating errors +// when running on versions of Go that do not support fuzzing. This was added in +// Go 1.18. + +package ber + +import ( + "os" + "testing" + "time" +) + +func FuzzDecodePacket(f *testing.F) { + // Seed the fuzz corpus with the test cases defined in suite_test.go + for _, tc := range testCases { + file := tc.File + + dataIn, err := os.ReadFile(file) + if err != nil { + f.Fatalf("failed to load file %s into fuzz corpus: %v", file, err) + continue + } + f.Add(dataIn) + } + + // Seed the fuzz corpus with data known to cause panics in the past + f.Add([]byte{0x09, 0x02, 0x85, 0x30}) + f.Add([]byte{0x09, 0x01, 0xcf}) + + // Set a limit on the length decoded in readPacket() since the call to + // make([]byte, length) can allocate up to MaxPacketLengthBytes which is + // currently 2 GB. This can cause memory related crashes when fuzzing in + // parallel or on memory constrained devices. + MaxPacketLengthBytes = 65536 + f.Fuzz(func(t *testing.T, data []byte) { + stime := time.Now() + p, err := DecodePacketErr(data) + + if e := time.Since(stime); e > (time.Millisecond * 500) { + t.Fatalf("DecodePacketErr took too long: %s", e) + } + + if p == nil && err == nil { + t.Fatalf("DecodePacketErr returned a nil packet and no error") + } + }) +} diff --git a/real.go b/real.go index 610a003..9f637a5 100644 --- a/real.go +++ b/real.go @@ -89,12 +89,18 @@ func parseBinaryFloat(v []byte) (float64, error) { case 0x02: expLen = 3 case 0x03: + if len(v) < 2 { + return 0.0, errors.New("invalid data") + } expLen = int(v[0]) if expLen > 8 { return 0.0, errors.New("too big value of exponent") } v = v[1:] } + if expLen > len(v) { + return 0.0, errors.New("too big value of exponent") + } buf, v = v[:expLen], v[expLen:] exponent, err := ParseInt64(buf) if err != nil {