Skip to content

Commit

Permalink
GODRIVER-2869 Two protocol validations to reduce client denial of ser…
Browse files Browse the repository at this point in the history
…vice risks (#1291)

Co-authored-by: Alan Parra <[email protected]>
Co-authored-by: Qingyang Hu <[email protected]>
  • Loading branch information
3 people committed Aug 1, 2023
1 parent 989b3e1 commit 436a982
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 0 deletions.
3 changes: 3 additions & 0 deletions x/bsonx/bsoncore/bsoncore.go
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,9 @@ func readLengthBytes(src []byte) ([]byte, []byte, bool) {
if !ok {
return nil, src, false
}
if l < 4 {
return nil, src, false
}
if len(src) < int(l) {
return nil, src, false
}
Expand Down
9 changes: 9 additions & 0 deletions x/bsonx/bsoncore/bsoncore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"testing"

"github.com/google/go-cmp/cmp"

"go.mongodb.org/mongo-driver/bson/bsontype"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/internal/assert"
Expand Down Expand Up @@ -943,6 +944,14 @@ func TestNullBytes(t *testing.T) {
})
}

func TestInvalidBytes(t *testing.T) {
t.Run("read length less than 4 int bytes", func(t *testing.T) {
_, src, ok := readLengthBytes([]byte{0x00, 0x00, 0x00, 0x01})
assert.False(t, ok, "expected not ok response for invalid length read")
assert.Equal(t, 4, len(src), "expected src to contain the size parameter still")
})
}

func compareDecimal128(d1, d2 primitive.Decimal128) bool {
d1H, d1L := d1.GetBytes()
d2H, d2L := d2.GetBytes()
Expand Down
6 changes: 6 additions & 0 deletions x/mongo/driver/compression.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ func DecompressPayload(in []byte, opts CompressionOpts) (uncompressed []byte, er
case wiremessage.CompressorNoOp:
return in, nil
case wiremessage.CompressorSnappy:
l, err := snappy.DecodedLen(in)
if err != nil {
return nil, fmt.Errorf("decoding compressed length %w", err)
} else if int32(l) != opts.UncompressedSize {
return nil, fmt.Errorf("unexpected decompression size, expected %v but got %v", opts.UncompressedSize, l)
}
uncompressed = make([]byte, opts.UncompressedSize)
return snappy.Decode(uncompressed, in)
case wiremessage.CompressorZLib:
Expand Down
17 changes: 17 additions & 0 deletions x/mongo/driver/compression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,23 @@ func TestCompression(t *testing.T) {
}
}

func TestDecompressFailures(t *testing.T) {
t.Run("snappy decompress huge size", func(t *testing.T) {
opts := CompressionOpts{
Compressor: wiremessage.CompressorSnappy,
UncompressedSize: 100, // reasonable size
}
// Compressed data is twice as large as declared above.
// In test we use actual compression so that the decompress action would pass without fix (thus failing test).
// When decompression starts it allocates a buffer of the defined size, regardless of a valid compressed body following.
compressedData, err := CompressPayload(make([]byte, opts.UncompressedSize*2), opts)
assert.NoError(t, err, "premature error making compressed example")

_, err = DecompressPayload(compressedData, opts)
assert.Error(t, err)
})
}

func BenchmarkCompressPayload(b *testing.B) {
payload := func() []byte {
buf, err := os.ReadFile("compression.go")
Expand Down

0 comments on commit 436a982

Please sign in to comment.