Skip to content

Commit 436a982

Browse files
jentfoocodingllamaqingyang-hu
committed
GODRIVER-2869 Two protocol validations to reduce client denial of service risks (#1291)
Co-authored-by: Alan Parra <[email protected]> Co-authored-by: Qingyang Hu <[email protected]>
1 parent 989b3e1 commit 436a982

File tree

4 files changed

+35
-0
lines changed

4 files changed

+35
-0
lines changed

x/bsonx/bsoncore/bsoncore.go

+3
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,9 @@ func readLengthBytes(src []byte) ([]byte, []byte, bool) {
825825
if !ok {
826826
return nil, src, false
827827
}
828+
if l < 4 {
829+
return nil, src, false
830+
}
828831
if len(src) < int(l) {
829832
return nil, src, false
830833
}

x/bsonx/bsoncore/bsoncore_test.go

+9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"testing"
1515

1616
"github.com/google/go-cmp/cmp"
17+
1718
"go.mongodb.org/mongo-driver/bson/bsontype"
1819
"go.mongodb.org/mongo-driver/bson/primitive"
1920
"go.mongodb.org/mongo-driver/internal/assert"
@@ -943,6 +944,14 @@ func TestNullBytes(t *testing.T) {
943944
})
944945
}
945946

947+
func TestInvalidBytes(t *testing.T) {
948+
t.Run("read length less than 4 int bytes", func(t *testing.T) {
949+
_, src, ok := readLengthBytes([]byte{0x00, 0x00, 0x00, 0x01})
950+
assert.False(t, ok, "expected not ok response for invalid length read")
951+
assert.Equal(t, 4, len(src), "expected src to contain the size parameter still")
952+
})
953+
}
954+
946955
func compareDecimal128(d1, d2 primitive.Decimal128) bool {
947956
d1H, d1L := d1.GetBytes()
948957
d2H, d2L := d2.GetBytes()

x/mongo/driver/compression.go

+6
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ func DecompressPayload(in []byte, opts CompressionOpts) (uncompressed []byte, er
111111
case wiremessage.CompressorNoOp:
112112
return in, nil
113113
case wiremessage.CompressorSnappy:
114+
l, err := snappy.DecodedLen(in)
115+
if err != nil {
116+
return nil, fmt.Errorf("decoding compressed length %w", err)
117+
} else if int32(l) != opts.UncompressedSize {
118+
return nil, fmt.Errorf("unexpected decompression size, expected %v but got %v", opts.UncompressedSize, l)
119+
}
114120
uncompressed = make([]byte, opts.UncompressedSize)
115121
return snappy.Decode(uncompressed, in)
116122
case wiremessage.CompressorZLib:

x/mongo/driver/compression_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,23 @@ func TestCompression(t *testing.T) {
4141
}
4242
}
4343

44+
func TestDecompressFailures(t *testing.T) {
45+
t.Run("snappy decompress huge size", func(t *testing.T) {
46+
opts := CompressionOpts{
47+
Compressor: wiremessage.CompressorSnappy,
48+
UncompressedSize: 100, // reasonable size
49+
}
50+
// Compressed data is twice as large as declared above.
51+
// In test we use actual compression so that the decompress action would pass without fix (thus failing test).
52+
// When decompression starts it allocates a buffer of the defined size, regardless of a valid compressed body following.
53+
compressedData, err := CompressPayload(make([]byte, opts.UncompressedSize*2), opts)
54+
assert.NoError(t, err, "premature error making compressed example")
55+
56+
_, err = DecompressPayload(compressedData, opts)
57+
assert.Error(t, err)
58+
})
59+
}
60+
4461
func BenchmarkCompressPayload(b *testing.B) {
4562
payload := func() []byte {
4663
buf, err := os.ReadFile("compression.go")

0 commit comments

Comments
 (0)