github.com/MerlinKodo/quic-go@v0.39.2/fuzzing/frames/fuzz.go (about) 1 package frames 2 3 import ( 4 "fmt" 5 6 "github.com/MerlinKodo/quic-go/internal/protocol" 7 "github.com/MerlinKodo/quic-go/internal/wire" 8 ) 9 10 const version = protocol.Version1 11 12 // PrefixLen is the number of bytes used for configuration 13 const PrefixLen = 1 14 15 func toEncLevel(v uint8) protocol.EncryptionLevel { 16 switch v % 3 { 17 default: 18 return protocol.EncryptionInitial 19 case 1: 20 return protocol.EncryptionHandshake 21 case 2: 22 return protocol.Encryption1RTT 23 } 24 } 25 26 // Fuzz fuzzes the QUIC frames. 27 // 28 //go:generate go run ./cmd/corpus.go 29 func Fuzz(data []byte) int { 30 if len(data) < PrefixLen { 31 return 0 32 } 33 encLevel := toEncLevel(data[0]) 34 data = data[PrefixLen:] 35 36 parser := wire.NewFrameParser(true) 37 parser.SetAckDelayExponent(protocol.DefaultAckDelayExponent) 38 39 var numFrames int 40 var b []byte 41 for len(data) > 0 { 42 initialLen := len(data) 43 l, f, err := parser.ParseNext(data, encLevel, version) 44 if err != nil { 45 break 46 } 47 data = data[l:] 48 numFrames++ 49 if f == nil { // PADDING frame 50 continue 51 } 52 // We accept empty STREAM frames, but we don't write them. 53 if sf, ok := f.(*wire.StreamFrame); ok { 54 if sf.DataLen() == 0 { 55 sf.PutBack() 56 continue 57 } 58 } 59 60 startLen := len(b) 61 parsedLen := initialLen - len(data) 62 b, err = f.Append(b, version) 63 if err != nil { 64 panic(fmt.Sprintf("Error writing frame %#v: %s", f, err)) 65 } 66 frameLen := protocol.ByteCount(len(b) - startLen) 67 if f.Length(version) != frameLen { 68 panic(fmt.Sprintf("Inconsistent frame length for %#v: expected %d, got %d", f, frameLen, f.Length(version))) 69 } 70 if sf, ok := f.(*wire.StreamFrame); ok { 71 sf.PutBack() 72 } 73 if frameLen > protocol.ByteCount(parsedLen) { 74 panic(fmt.Sprintf("Serialized length (%d) is longer than parsed length (%d)", len(b), parsedLen)) 75 } 76 } 77 78 if numFrames == 0 { 79 return 0 80 } 81 return 1 82 }