fuzz the frame parser

This commit is contained in:
Marten Seemann 2019-08-22 12:53:08 +07:00
parent d77368af36
commit 20557738a0
65 changed files with 408 additions and 6 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,2 @@
� MV����c1��H+���W���@���2m�G�3=(�
��;��NW�%��Аu�y��$M���������

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
s ���

View file

@ -0,0 +1 @@
Ą ´ŮÉ ÝťRß×›MvB›az źź ;Ą[ ŔÖL�…5„Ëŕp›X?aÓuĽ´ôů)áŹÚžo‚ĺNtŽ�çžK˝oăLÜş„>čÖ>ŚOţëęTmŹ¬Ý¬Î.˘‡|UyϢǎ

View file

@ -0,0 +1 @@
�74

View file

@ -0,0 +1 @@
¦z‹˙˙˙˙˙˙˙˙

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
$–ΈF2Φ¦²ϊΩ�mσD�)f{.΄@UoεΛ@[1p¬¬¥Η[―{pθaDΣΊk;Xώ

View file

@ -0,0 +1,2 @@
Ô
ByPçĐOL&ëá

View file

@ -0,0 +1 @@
?イlコQ

View file

@ -0,0 +1 @@
���������

View file

@ -0,0 +1 @@
�5��M

View file

@ -0,0 +1 @@
p��������

Binary file not shown.

View file

@ -0,0 +1 @@
M���

View file

@ -0,0 +1 @@
/'

View file

@ -0,0 +1 @@
�R�

View file

@ -0,0 +1 @@
P��������

View file

@ -0,0 +1 @@
o/

View file

@ -0,0 +1 @@
��g���������

View file

@ -0,0 +1 @@
îE

View file

@ -0,0 +1 @@
�L�

View file

@ -0,0 +1 @@


Binary file not shown.

View file

@ -0,0 +1 @@
C .T^'?ãWkoí'ÿ‰tºÀÊýšÐV’±6ç8–MýÇž�SCsfýf×Oì‰I·#n

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,2 @@
€¶ÏÚî@d Ï Þjÿ™CíÊo–¿MÚð �OÍjËÛ³ö1”P5†¨¦X®`µîSšµ­òº#ܦgߦULYJ,€kߤçVäX´‹®I .£Uélû‰Ì«ò��yMž‚ý
rTñ³”öê¼f

View file

@ -0,0 +1 @@
� ��ҕ�H���G(����+^��

View file

@ -0,0 +1 @@
ËF­F­ÓÔ˙ćŐ™VQ__S‡ä”f™Ł®ÁJ|¶®»

Binary file not shown.

View file

@ -0,0 +1 @@
_�3D ��d�

View file

@ -0,0 +1 @@
� g���������Ku!�g

View file

@ -0,0 +1 @@
с ��В_џџџџџџџџЮІшПF`ёо��

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
F

76
fuzzing/frames/fuzz.go Normal file
View file

@ -0,0 +1,76 @@
// +build gofuzz
package frames
import (
"bytes"
"fmt"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/wire"
)
const version = protocol.VersionTLS
func Fuzz(data []byte) int {
if len(data) < 1 {
return 0
}
parser := wire.NewFrameParser(version)
parser.SetAckDelayExponent(protocol.DefaultAckDelayExponent)
var encLevel protocol.EncryptionLevel
switch data[0] % 3 {
case 0:
encLevel = protocol.EncryptionInitial
case 1:
encLevel = protocol.EncryptionHandshake
case 2:
encLevel = protocol.Encryption1RTT
}
data = data[1:]
r := bytes.NewReader(data)
initialLen := r.Len()
var frames []wire.Frame
for r.Len() > 0 {
f, err := parser.ParseNext(r, encLevel)
if err != nil {
break
}
frames = append(frames, f)
}
parsedLen := initialLen - r.Len()
if len(frames) == 0 {
return 0
}
b := &bytes.Buffer{}
for _, f := range frames {
if f == nil { // PADDING frame
b.WriteByte(0x0)
continue
}
// We accept empty STREAM frames, but we don't write them.
if sf, ok := f.(*wire.StreamFrame); ok {
if sf.DataLen() == 0 {
continue
}
}
lenBefore := b.Len()
if err := f.Write(b, version); err != nil {
panic(fmt.Sprintf("Error writing frame %#v: %s", f, err))
}
frameLen := b.Len() - lenBefore
if f.Length(version) != protocol.ByteCount(frameLen) {
panic(fmt.Sprintf("Inconsistent frame length for %#v: expected %d, got %d", f, frameLen, f.Length(version)))
}
}
if b.Len() > parsedLen {
panic(fmt.Sprintf("Serialized length (%d) is longer than parsed length (%d)", b.Len(), parsedLen))
}
return 0
}

289
fuzzing/frames/main.go Normal file
View file

@ -0,0 +1,289 @@
// +build !gofuzz
package main
import (
"bytes"
"fmt"
"math/rand"
"os"
"time"
"github.com/lucas-clemente/quic-go"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/qerr"
"github.com/lucas-clemente/quic-go/internal/wire"
)
const version = protocol.VersionTLS
func getRandomData(l int) []byte {
b := make([]byte, l)
rand.Read(b)
return b
}
func getRandomNumber() uint64 {
switch 1 << uint8(rand.Intn(3)) {
case 1:
return uint64(rand.Int63n(64))
case 2:
return uint64(rand.Int63n(16384))
case 4:
return uint64(rand.Int63n(1073741824))
case 8:
return uint64(rand.Int63n(4611686018427387904))
default:
panic("unexpected length")
}
}
func getRandomNumberLowerOrEqual(target uint64) uint64 {
if target == 0 {
return 0
}
return uint64(rand.Int63n(int64(target)))
}
// returns a *maximum* number of num ACK ranges
func getAckRanges(num int) []wire.AckRange {
var ranges []wire.AckRange
prevSmallest := uint64(rand.Int63n(4611686018427387904))
for i := 0; i < num; i++ {
if prevSmallest <= 2 {
break
}
largest := getRandomNumberLowerOrEqual(prevSmallest - 2)
smallest := getRandomNumberLowerOrEqual(largest)
ranges = append(ranges, wire.AckRange{
Smallest: protocol.PacketNumber(smallest),
Largest: protocol.PacketNumber(largest),
})
prevSmallest = smallest
}
return ranges
}
func getFrames() []wire.Frame {
frames := []wire.Frame{
&wire.StreamFrame{ // STREAM frame at 0 offset, with FIN bit
StreamID: protocol.StreamID(getRandomNumber()),
FinBit: true,
},
&wire.StreamFrame{ // STREAM frame at 0 offset, with data and FIN bit
StreamID: protocol.StreamID(getRandomNumber()),
FinBit: true,
Data: getRandomData(100),
},
&wire.StreamFrame{ // STREAM frame at non-zero offset, with data
StreamID: protocol.StreamID(getRandomNumber()),
Offset: protocol.ByteCount(getRandomNumber()),
Data: getRandomData(50),
},
&wire.StreamFrame{ // STREAM frame at non-zero offset, with data and FIN bit
StreamID: protocol.StreamID(getRandomNumber()),
Offset: protocol.ByteCount(getRandomNumber()),
Data: getRandomData(50),
FinBit: true,
},
&wire.StreamFrame{ // STREAM frame at maximum offset, with FIN bit
StreamID: protocol.StreamID(getRandomNumber()),
Offset: protocol.MaxByteCount - 5,
Data: getRandomData(5),
FinBit: true,
},
&wire.StreamFrame{ // STREAM frame with data at maximum offset
StreamID: protocol.StreamID(getRandomNumber()),
Offset: protocol.MaxByteCount,
Data: getRandomData(10),
},
&wire.AckFrame{
AckRanges: getAckRanges(1),
DelayTime: time.Duration(getRandomNumber()),
},
&wire.AckFrame{
AckRanges: getAckRanges(5),
DelayTime: time.Duration(getRandomNumber()),
},
&wire.AckFrame{
AckRanges: getAckRanges(300),
DelayTime: time.Duration(getRandomNumber()),
},
&wire.PingFrame{},
&wire.ResetStreamFrame{
StreamID: protocol.StreamID(getRandomNumber()),
ErrorCode: quic.ErrorCode(getRandomNumber()),
ByteOffset: protocol.ByteCount(getRandomNumber()),
},
&wire.ResetStreamFrame{ // at maximum offset
StreamID: protocol.StreamID(getRandomNumber()),
ErrorCode: quic.ErrorCode(getRandomNumber()),
ByteOffset: protocol.MaxByteCount,
},
&wire.StopSendingFrame{
StreamID: protocol.StreamID(getRandomNumber()),
ErrorCode: quic.ErrorCode(getRandomNumber()),
},
&wire.CryptoFrame{
Data: getRandomData(100),
},
&wire.CryptoFrame{
Offset: protocol.ByteCount(getRandomNumber()),
Data: getRandomData(50),
},
&wire.NewTokenFrame{
Token: getRandomData(10),
},
&wire.MaxDataFrame{
ByteOffset: protocol.ByteCount(getRandomNumber()),
},
&wire.MaxDataFrame{
ByteOffset: protocol.MaxByteCount,
},
&wire.MaxStreamDataFrame{
StreamID: protocol.StreamID(getRandomNumber()),
ByteOffset: protocol.ByteCount(getRandomNumber()),
},
&wire.MaxStreamDataFrame{
StreamID: protocol.StreamID(getRandomNumber()),
ByteOffset: protocol.MaxByteCount,
},
&wire.MaxStreamsFrame{
Type: protocol.StreamTypeUni,
MaxStreamNum: protocol.StreamNum(getRandomNumber()),
},
&wire.MaxStreamsFrame{
Type: protocol.StreamTypeBidi,
MaxStreamNum: protocol.StreamNum(getRandomNumber()),
},
&wire.DataBlockedFrame{
DataLimit: protocol.ByteCount(getRandomNumber()),
},
&wire.DataBlockedFrame{
DataLimit: protocol.MaxByteCount,
},
&wire.StreamDataBlockedFrame{
StreamID: protocol.StreamID(getRandomNumber()),
DataLimit: protocol.ByteCount(getRandomNumber()),
},
&wire.StreamDataBlockedFrame{
StreamID: protocol.StreamID(getRandomNumber()),
DataLimit: protocol.MaxByteCount,
},
&wire.StreamsBlockedFrame{
Type: protocol.StreamTypeUni,
StreamLimit: protocol.StreamNum(getRandomNumber()),
},
&wire.StreamsBlockedFrame{
Type: protocol.StreamTypeBidi,
StreamLimit: protocol.StreamNum(getRandomNumber()),
},
&wire.RetireConnectionIDFrame{
SequenceNumber: getRandomNumber(),
},
&wire.ConnectionCloseFrame{ // QUIC error with empty reason
IsApplicationError: false,
ErrorCode: qerr.ErrorCode(getRandomNumber()),
ReasonPhrase: "",
},
&wire.ConnectionCloseFrame{ // QUIC error with reason
IsApplicationError: false,
// TODO: add frame type
ErrorCode: qerr.ErrorCode(getRandomNumber()),
ReasonPhrase: string(getRandomData(100)),
},
&wire.ConnectionCloseFrame{ // application error with empty reason
IsApplicationError: true,
ErrorCode: qerr.ErrorCode(getRandomNumber()),
ReasonPhrase: "",
},
&wire.ConnectionCloseFrame{ // application error with reason
IsApplicationError: true,
ErrorCode: qerr.ErrorCode(getRandomNumber()),
ReasonPhrase: string(getRandomData(100)),
},
}
seq1 := getRandomNumber()
seq2 := getRandomNumber()
var token1, token2 [16]byte
copy(token1[:], getRandomData(16))
copy(token2[:], getRandomData(16))
frames = append(frames, []wire.Frame{
&wire.NewConnectionIDFrame{
SequenceNumber: seq1,
RetirePriorTo: seq1 / 2,
ConnectionID: getRandomData(4),
StatelessResetToken: token1,
},
&wire.NewConnectionIDFrame{
SequenceNumber: seq2,
RetirePriorTo: seq2,
ConnectionID: getRandomData(17),
StatelessResetToken: token2,
},
}...)
var data1 [8]byte
copy(data1[:], getRandomData(8))
frames = append(frames, &wire.PathChallengeFrame{
Data: data1,
})
var data2 [8]byte
copy(data2[:], getRandomData(8))
frames = append(frames, &wire.PathResponseFrame{
Data: data2,
})
return frames
}
func main() {
rand.Seed(42)
for i, f := range getFrames() {
b := &bytes.Buffer{}
if err := f.Write(b, version); err != nil {
panic(err)
}
if err := writeCorpusFile(fmt.Sprintf("single-frame-%d", i), b.Bytes()); err != nil {
panic(err)
}
}
for i := 0; i < 25; i++ {
frames := getFrames()
b := &bytes.Buffer{}
for j := 0; j < rand.Intn(30)+2; j++ {
if rand.Intn(10) == 0 { // write a PADDING frame
b.WriteByte(0x0)
}
f := frames[rand.Intn(len(frames))]
if err := f.Write(b, version); err != nil {
panic(err)
}
if rand.Intn(10) == 0 { // write a PADDING frame
b.WriteByte(0x0)
}
}
if err := writeCorpusFile(fmt.Sprintf("multiple-frames-%d", i), b.Bytes()); err != nil {
panic(err)
}
}
}
func writeCorpusFile(name string, data []byte) error {
file, err := os.Create("corpus/" + name)
if err != nil {
return err
}
data = append(getRandomData(1), data...)
if _, err := file.Write(data); err != nil {
return err
}
return file.Close()
}