forked from quic-go/quic-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fuzz.go
132 lines (121 loc) · 3.41 KB
/
fuzz.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package frames
import (
"fmt"
"github.com/YCK1130/quic-go/internal/protocol"
"github.com/YCK1130/quic-go/internal/wire"
)
const version = protocol.Version1
// PrefixLen is the number of bytes used for configuration
const PrefixLen = 1
func toEncLevel(v uint8) protocol.EncryptionLevel {
switch v % 3 {
default:
return protocol.EncryptionInitial
case 1:
return protocol.EncryptionHandshake
case 2:
return protocol.Encryption1RTT
}
}
// Fuzz fuzzes the QUIC frames.
//
//go:generate go run ./cmd/corpus.go
func Fuzz(data []byte) int {
if len(data) < PrefixLen {
return 0
}
encLevel := toEncLevel(data[0])
data = data[PrefixLen:]
parser := wire.NewFrameParser(true)
parser.SetAckDelayExponent(protocol.DefaultAckDelayExponent)
var numFrames int
var b []byte
for len(data) > 0 {
initialLen := len(data)
l, f, err := parser.ParseNext(data, encLevel, version)
if err != nil {
break
}
data = data[l:]
numFrames++
if f == nil { // PADDING frame
continue
}
// We accept empty STREAM frames, but we don't write them.
if sf, ok := f.(*wire.StreamFrame); ok {
if sf.DataLen() == 0 {
sf.PutBack()
continue
}
}
validateFrame(f)
startLen := len(b)
parsedLen := initialLen - len(data)
b, err = f.Append(b, version)
if err != nil {
panic(fmt.Sprintf("error writing frame %#v: %s", f, err))
}
frameLen := protocol.ByteCount(len(b) - startLen)
if f.Length(version) != frameLen {
panic(fmt.Sprintf("inconsistent frame length for %#v: expected %d, got %d", f, frameLen, f.Length(version)))
}
if sf, ok := f.(*wire.StreamFrame); ok {
sf.PutBack()
}
if frameLen > protocol.ByteCount(parsedLen) {
panic(fmt.Sprintf("serialized length (%d) is longer than parsed length (%d)", len(b), parsedLen))
}
}
if numFrames == 0 {
return 0
}
return 1
}
func validateFrame(frame wire.Frame) {
switch f := frame.(type) {
case *wire.StreamFrame:
if protocol.ByteCount(len(f.Data)) != f.DataLen() {
panic("STREAM frame: inconsistent data length")
}
case *wire.AckFrame:
if f.DelayTime < 0 {
panic(fmt.Sprintf("invalid ACK delay_time: %s", f.DelayTime))
}
if f.LargestAcked() < f.LowestAcked() {
panic("ACK: largest acknowledged is smaller than lowest acknowledged")
}
for _, r := range f.AckRanges {
if r.Largest < 0 || r.Smallest < 0 {
panic("ACK range contains a negative packet number")
}
}
if !f.AcksPacket(f.LargestAcked()) {
panic("ACK frame claims that largest acknowledged is not acknowledged")
}
if !f.AcksPacket(f.LowestAcked()) {
panic("ACK frame claims that lowest acknowledged is not acknowledged")
}
_ = f.AcksPacket(100)
_ = f.AcksPacket((f.LargestAcked() + f.LowestAcked()) / 2)
case *wire.NewConnectionIDFrame:
if f.ConnectionID.Len() < 1 || f.ConnectionID.Len() > 20 {
panic(fmt.Sprintf("invalid NEW_CONNECTION_ID frame length: %s", f.ConnectionID))
}
case *wire.NewTokenFrame:
if len(f.Token) == 0 {
panic("NEW_TOKEN frame with an empty token")
}
case *wire.MaxStreamsFrame:
if f.MaxStreamNum > protocol.MaxStreamCount {
panic("MAX_STREAMS frame with an invalid Maximum Streams value")
}
case *wire.StreamsBlockedFrame:
if f.StreamLimit > protocol.MaxStreamCount {
panic("STREAMS_BLOCKED frame with an invalid Maximum Streams value")
}
case *wire.ConnectionCloseFrame:
if f.IsApplicationError && f.FrameType != 0 {
panic("CONNECTION_CLOSE for an application error containing a frame type")
}
}
}