[OSS-fuzz] Fix FuzzMongoRead (#14807)

Co-authored-by: Marek Smoliński <marek@goteleport.com>
Co-authored-by: Zac Bergquist <zac.bergquist@goteleport.com>
This commit is contained in:
Jakub Nyckowski 2022-08-01 11:21:11 -04:00 committed by GitHub
parent ecdb9dfff7
commit 925351e5be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 114 additions and 3 deletions

View file

@ -25,7 +25,72 @@ import (
func FuzzMongoRead(f *testing.F) {
f.Add([]byte{})
f.Add([]byte(" \x00\x00\x0000000000\xdc\a\x00\x000000000\xca\x010000000"))
f.Add([]byte(" \x00\x00\x0000000000\xdd\a\x00\x000000\x01000\x8e0000000000000"))
f.Add([]byte(" \x00\x00\x0000000000\xdd\a\x00\x00000000000\x01\x02\x00\x00\x0000"))
f.Add([]byte(" \x00\x00\x0000000000\xdd\a\x00\x00000000000\x01\x01\x00\x00\x0000"))
f.Add([]byte("0\x00\x00\x0000000000\x01\x00\x00\x0000000000000000000000\x03\x00\x00\x00\x00\x00\x00\x000000"))
f.Add([]byte(" \x00\x00\x0000000000\xd2\a\x00\x000000\x00\x00\x00\x00\x00\x00000000"))
f.Add([]byte("000\xa4000000000000"))
f.Add([]byte("0\x00\x00\x0000@00000\x01\x00\x00\x000000000000000000000\x01\x00\x00\x00\x0000000000"))
f.Add([]byte(" \x00\x00\x0000000000\xdd\a\x00\x00000000000000\x01000"))
f.Add([]byte{0x3f, 0x2d, 0x0, 0x0, 0x0, 0xf7, 0xfe, 0x0, 0xff, 0xff, 0xff, 0x29, 0xff, 0xdc, 0x7, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x71, 0x1, 0xff, 0xff, 0x2e, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xb4,
0x1a, 0x54, 0x6d, 0xff, 0xff, 0x0, 0xff, 0x53, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6, 0x36,
0xd0, 0x4, 0x0, 0x84, 0x0, 0x0, 0x4, 0x29, 0x0})
f.Add([]byte{0x1d, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x0, 0x0, 0x30, 0x13, 0x0, 0x0, 0xdc, 0x7, 0x0, 0x0, 0x30, 0x20,
0x1d, 0x1d, 0x3, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, 0x65, 0x0, 0xe2, 0xff, 0xff, 0xe2, 0x1d, 0x0, 0x0})
f.Add([]byte{0x7e, 0x1c, 0x0, 0x0, 0x0, 0x0, 0xd3, 0xc3, 0xd1, 0x26, 0x0, 0xfd, 0xa5, 0xdd, 0x7, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0xa6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa5, 0xa5, 0xa5,
0x7, 0x0, 0x0, 0xa5, 0xff, 0x9, 0x0, 0x0, 0xa5, 0xa5, 0x2a, 0xa5, 0xa5, 0x0, 0x0, 0x0, 0xa5, 0x10, 0xa5, 0xd3,
0xc3, 0xd1, 0x26, 0x0, 0xfd, 0xa5})
f.Add([]byte{0x42, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x9, 0x0, 0x0, 0x0, 0x0, 0xdd, 0x7, 0x0, 0x0, 0x13, 0xa9,
0x29, 0x13, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0x2,
0xa, 0x16, 0x60, 0x56, 0x56, 0x56, 0xff, 0xa9, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0xa9, 0xa9, 0x0, 0xdc,
0x7, 0x0, 0x0, 0xd4, 0x7, 0x0, 0x0, 0x11, 0x0, 0x92, 0x76, 0x76, 0xa9, 0x76, 0x76})
f.Add([]byte{0x1c, 0x1a, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xdd, 0x7, 0x0, 0x0, 0x12, 0x0, 0x0,
0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26, 0x0, 0x80, 0xa, 0x0, 0x0, 0x15, 0x0, 0x0, 0x0})
f.Add([]byte{0x30, 0x30, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1, 0x0, 0x0, 0x0, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x4, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0})
f.Add([]byte{0x60, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x0, 0x0, 0xaa, 0xdc, 0x7, 0x0, 0x0, 0x0, 0x0,
0x68, 0x0, 0x11, 0x1, 0x0, 0x3f, 0x1, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5,
0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5,
0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5,
0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x3b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0xa4})
f.Add([]byte{0x43, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x30, 0x30, 0xd2, 0x7, 0x0, 0x0, 0x1, 0x10,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
0x3c, 0x3c, 0x3c, 0xb})
f.Add([]byte{0x47, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13, 0x1, 0x0, 0x0, 0x0, 0xbf, 0xbf,
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb,
0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x1, 0x0, 0x0, 0x4e, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x20, 0x32, 0x1, 0x1, 0xff, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff})
f.Add([]byte{0x30, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xdd, 0x7, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xd6, 0x7, 0x0, 0x0, 0xfe, 0x1d, 0x0, 0x3a, 0x0, 0x0, 0x3a, 0x3a, 0x3a,
0x31, 0x3a, 0x3a, 0x2a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x0, 0x7a, 0x0})
f.Add([]byte{0x26, 0x24, 0x00, 0x00, 0x00, 0xdd, 0xff, 0xc7, 0xff, 0xff, 0xde, 0xff,
0xf6, 0xdd, 0x07, 0x00, 0x00, 0x23, 0xad, 0x00, 0x39, 0x01, 0x00, 0x07,
0xd7, 0x8e, 0x7e, 0xdf, 0x50, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x26,
0x24, 0xe2, 0xff, 0xff, 0x06, 0xd6, 0xff, 0x77, 0x10, 0x00,
})
f.Fuzz(func(t *testing.T, msgBytes []byte) {
msg := bytes.NewReader(msgBytes)

View file

@ -114,6 +114,10 @@ func readOpCompressed(header MessageHeader, payload []byte) (message *MessageOpC
CompressedMessage: compressedMessage,
bytes: append(header.bytes[:], payload...),
}
if uncompressedSize <= 0 || len(compressedMessage) == 0 {
return nil, trace.BadParameter("malformed OP_COMPRESSED: invalid message size %v", payload)
}
message.originalMessage, err = decompress(message)
if err != nil {
return nil, trace.Wrap(err)

View file

@ -97,7 +97,7 @@ func readOpInsert(header MessageHeader, payload []byte) (*MessageOpInsert, error
for len(rem) > 0 {
var document bsoncore.Document
document, rem, ok = bsoncore.ReadDocument(rem)
if !ok {
if !ok || len(document) == 0 {
return nil, trace.BadParameter("malformed OP_INSERT: missing document %v", payload)
}
documents = append(documents, document)

View file

@ -251,6 +251,11 @@ func readOpMsg(header MessageHeader, payload []byte) (*MessageOpMsg, error) {
case wiremessage.DocumentSequence:
var id string
var docs []bsoncore.Document
if err := validateDocumentSize(rem); err != nil {
return nil, trace.BadParameter("malformed OP_MSG: %v %v", err, payload)
}
id, docs, rem, ok = wiremessage.ReadMsgSectionDocumentSequence(rem)
if !ok {
return nil, trace.BadParameter("malformed OP_MSG: missing document sequence section %v", payload)
@ -274,6 +279,23 @@ func readOpMsg(header MessageHeader, payload []byte) (*MessageOpMsg, error) {
}, nil
}
// validateDocumentSize validates document length encoded in the message.
func validateDocumentSize(src []byte) error {
const headerLen = 4
if len(src) < headerLen {
return trace.BadParameter("document is too short")
}
// document length is encoded in the first 4 bytes
documentLength := int(int32(src[0]) | int32(src[1])<<8 | int32(src[2])<<16 | int32(src[3])<<24)
// document payload cannot be shorter than the size of the whole message plus the header length.
if documentLength+headerLen <= len(src) {
return trace.BadParameter("invalid document length")
}
return nil
}
// ToWire converts this message to wire protocol message bytes.
//
// https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/#op_msg

View file

@ -49,7 +49,7 @@ func MakeOpReply(document bsoncore.Document) *MessageOpReply {
}
}
// MakeOpReply is a shorthand to create OP_REPLY message from a single document
// MakeOpReplyWithFlags is a shorthand to create OP_REPLY message from a single document
// with provided flags.
func MakeOpReplyWithFlags(document bsoncore.Document, flags wiremessage.ReplyFlag) *MessageOpReply {
return &MessageOpReply{
@ -123,7 +123,7 @@ func readOpReply(header MessageHeader, payload []byte) (*MessageOpReply, error)
if !ok {
return nil, trace.BadParameter("malformed OP_REPLY: missing number returned %v", payload)
}
documents, _, ok := wiremessage.ReadReplyDocuments(rem)
documents, _, ok := ReadReplyDocuments(rem)
if !ok {
return nil, trace.BadParameter("malformed OP_REPLY: missing documents %v", payload)
}
@ -138,6 +138,26 @@ func readOpReply(header MessageHeader, payload []byte) (*MessageOpReply, error)
}, nil
}
// ReadReplyDocuments reads multiple documents from the source.
//
// This function works in the same way as wiremessage.ReadReplyDocuments except, it can handle document of size 0.
// When a document of size 0 is passed to wiremessage.ReadReplyDocuments, it will keep creating empty documents until
// it uses all system memory/application crash.
func ReadReplyDocuments(src []byte) (docs []bsoncore.Document, rem []byte, ok bool) {
rem = src
for {
var doc bsoncore.Document
doc, rem, ok = bsoncore.ReadDocument(rem)
if !ok || len(doc) == 0 {
break
}
docs = append(docs, doc)
}
return docs, rem, true
}
// ToWire converts this message to wire protocol message bytes.
//
// https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/#op_reply