github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/fuzzing/frames/fuzz.go (about) 1 package frames 2 3 import ( 4 "fmt" 5 6 "github.com/metacubex/quic-go/internal/protocol" 7 "github.com/metacubex/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 validateFrame(f) 60 61 startLen := len(b) 62 parsedLen := initialLen - len(data) 63 b, err = f.Append(b, version) 64 if err != nil { 65 panic(fmt.Sprintf("error writing frame %#v: %s", f, err)) 66 } 67 frameLen := protocol.ByteCount(len(b) - startLen) 68 if f.Length(version) != frameLen { 69 panic(fmt.Sprintf("inconsistent frame length for %#v: expected %d, got %d", f, frameLen, f.Length(version))) 70 } 71 if sf, ok := f.(*wire.StreamFrame); ok { 72 sf.PutBack() 73 } 74 if frameLen > protocol.ByteCount(parsedLen) { 75 panic(fmt.Sprintf("serialized length (%d) is longer than parsed length (%d)", len(b), parsedLen)) 76 } 77 } 78 79 if numFrames == 0 { 80 return 0 81 } 82 return 1 83 } 84 85 func validateFrame(frame wire.Frame) { 86 switch f := frame.(type) { 87 case *wire.StreamFrame: 88 if protocol.ByteCount(len(f.Data)) != f.DataLen() { 89 panic("STREAM frame: inconsistent data length") 90 } 91 case *wire.AckFrame: 92 if f.DelayTime < 0 { 93 panic(fmt.Sprintf("invalid ACK delay_time: %s", f.DelayTime)) 94 } 95 if f.LargestAcked() < f.LowestAcked() { 96 panic("ACK: largest acknowledged is smaller than lowest acknowledged") 97 } 98 for _, r := range f.AckRanges { 99 if r.Largest < 0 || r.Smallest < 0 { 100 panic("ACK range contains a negative packet number") 101 } 102 } 103 if !f.AcksPacket(f.LargestAcked()) { 104 panic("ACK frame claims that largest acknowledged is not acknowledged") 105 } 106 if !f.AcksPacket(f.LowestAcked()) { 107 panic("ACK frame claims that lowest acknowledged is not acknowledged") 108 } 109 _ = f.AcksPacket(100) 110 _ = f.AcksPacket((f.LargestAcked() + f.LowestAcked()) / 2) 111 case *wire.NewConnectionIDFrame: 112 if f.ConnectionID.Len() < 1 || f.ConnectionID.Len() > 20 { 113 panic(fmt.Sprintf("invalid NEW_CONNECTION_ID frame length: %s", f.ConnectionID)) 114 } 115 case *wire.NewTokenFrame: 116 if len(f.Token) == 0 { 117 panic("NEW_TOKEN frame with an empty token") 118 } 119 case *wire.MaxStreamsFrame: 120 if f.MaxStreamNum > protocol.MaxStreamCount { 121 panic("MAX_STREAMS frame with an invalid Maximum Streams value") 122 } 123 case *wire.StreamsBlockedFrame: 124 if f.StreamLimit > protocol.MaxStreamCount { 125 panic("STREAMS_BLOCKED frame with an invalid Maximum Streams value") 126 } 127 case *wire.ConnectionCloseFrame: 128 if f.IsApplicationError && f.FrameType != 0 { 129 panic("CONNECTION_CLOSE for an application error containing a frame type") 130 } 131 } 132 }