Skip to content

Commit fc75cb4

Browse files
CSHARP-2760: All binary message encoders should verify the opcode when decoding a message
1 parent b0b1134 commit fc75cb4

14 files changed

+180
-31
lines changed

src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/DeleteMessageBinaryEncoder.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
using System;
1717
using System.IO;
18-
using System.Text;
1918
using MongoDB.Bson;
2019
using MongoDB.Bson.IO;
2120
using MongoDB.Bson.Serialization;
@@ -69,7 +68,8 @@ internal DeleteMessage ReadMessage<TDocument>(IBsonSerializer<TDocument> seriali
6968
stream.ReadInt32(); // messageSize
7069
var requestId = stream.ReadInt32();
7170
stream.ReadInt32(); // responseTo
72-
stream.ReadInt32(); // opcode
71+
var opcode = (Opcode)stream.ReadInt32();
72+
EnsureOpcodeIsValid(opcode);
7373
stream.ReadInt32(); // reserved
7474
var fullCollectionName = stream.ReadCString(Encoding);
7575
var flags = (DeleteFlags)stream.ReadInt32();
@@ -109,6 +109,15 @@ public void WriteMessage(DeleteMessage message)
109109
stream.BackpatchSize(startPosition);
110110
}
111111

112+
// private methods
113+
private void EnsureOpcodeIsValid(Opcode opcode)
114+
{
115+
if (opcode != Opcode.Delete)
116+
{
117+
throw new FormatException("Delete message opcode is not OP_DELETE.");
118+
}
119+
}
120+
112121
// explicit interface implementations
113122
MongoDBMessage IMessageEncoder.ReadMessage()
114123
{

src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/GetMoreMessageBinaryEncoder.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
using System;
1717
using System.IO;
18-
using System.Text;
1918
using MongoDB.Bson.IO;
2019
using MongoDB.Driver.Core.Misc;
2120

@@ -50,7 +49,8 @@ public GetMoreMessage ReadMessage()
5049
stream.ReadInt32(); // messageSize
5150
var requestId = stream.ReadInt32();
5251
stream.ReadInt32(); // responseTo
53-
stream.ReadInt32(); // opcode
52+
var opcode = (Opcode)stream.ReadInt32();
53+
EnsureOpcodeIsValid(opcode);
5454
stream.ReadInt32(); // reserved
5555
var fullCollectionName = stream.ReadCString(Encoding);
5656
var batchSize = stream.ReadInt32();
@@ -86,6 +86,15 @@ public void WriteMessage(GetMoreMessage message)
8686
stream.BackpatchSize(startPosition);
8787
}
8888

89+
// private methods
90+
private void EnsureOpcodeIsValid(Opcode opcode)
91+
{
92+
if (opcode != Opcode.GetMore)
93+
{
94+
throw new FormatException("GetMore message opcode is not OP_GET_MORE.");
95+
}
96+
}
97+
8998
// explicit interface implementations
9099
MongoDBMessage IMessageEncoder.ReadMessage()
91100
{

src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/InsertMessageBinaryEncoder.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ public InsertMessage<TDocument> ReadMessage()
6060
var messageSize = stream.ReadInt32();
6161
var requestId = stream.ReadInt32();
6262
stream.ReadInt32(); // responseTo
63-
stream.ReadInt32(); // opcode
63+
var opcode = (Opcode)stream.ReadInt32();
64+
EnsureOpcodeIsValid(opcode);
6465
var flags = (InsertFlags)stream.ReadInt32();
6566
var fullCollectionName = stream.ReadCString(Encoding);
6667
var documents = ReadDocuments(reader, messageStartPosition, messageSize);
@@ -113,6 +114,14 @@ private InsertFlags BuildInsertFlags(InsertMessage<TDocument> message)
113114
return flags;
114115
}
115116

117+
private void EnsureOpcodeIsValid(Opcode opcode)
118+
{
119+
if (opcode != Opcode.Insert)
120+
{
121+
throw new FormatException("Insert message opcode is not OP_INSERT.");
122+
}
123+
}
124+
116125
private List<TDocument> ReadDocuments(BsonBinaryReader reader, long messageStartPosition, int messageSize)
117126
{
118127
var stream = reader.BsonStream;

src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/KillCursorsMessageBinaryEncoder.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
using System;
1717
using System.IO;
18-
using System.Text;
1918
using MongoDB.Bson.IO;
2019
using MongoDB.Driver.Core.Misc;
2120

@@ -50,7 +49,8 @@ public KillCursorsMessage ReadMessage()
5049
stream.ReadInt32(); // messageSize
5150
var requestId = stream.ReadInt32();
5251
stream.ReadInt32(); // responseTo
53-
stream.ReadInt32(); // opcode
52+
var opcode = (Opcode)stream.ReadInt32();
53+
EnsureOpcodeIsValid(opcode);
5454
stream.ReadInt32(); // reserved
5555
var count = stream.ReadInt32();
5656
var cursorIds = new long[count];
@@ -89,6 +89,15 @@ public void WriteMessage(KillCursorsMessage message)
8989
stream.BackpatchSize(startPosition);
9090
}
9191

92+
// private methods
93+
private void EnsureOpcodeIsValid(Opcode opcode)
94+
{
95+
if (opcode != Opcode.KillCursors)
96+
{
97+
throw new FormatException("KillCursors message opcode is not OP_KILL_CURSORS.");
98+
}
99+
}
100+
92101
// explicit interface implementations
93102
MongoDBMessage IMessageEncoder.ReadMessage()
94103
{

src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ internal QueryMessage ReadMessage<TDocument>(IBsonSerializer<TDocument> serializ
8989
var messageSize = stream.ReadInt32();
9090
var requestId = stream.ReadInt32();
9191
stream.ReadInt32(); // responseTo
92-
stream.ReadInt32(); // opcode
92+
var opcode = (Opcode)stream.ReadInt32();
93+
EnsureOpcodeIsValid(opcode);
9394
var flags = (QueryFlags)stream.ReadInt32();
9495
var fullCollectionName = stream.ReadCString(Encoding);
9596
var skip = stream.ReadInt32();
@@ -153,6 +154,14 @@ public void WriteMessage(QueryMessage message)
153154
}
154155

155156
// private methods
157+
private void EnsureOpcodeIsValid(Opcode opcode)
158+
{
159+
if (opcode != Opcode.Query)
160+
{
161+
throw new FormatException("Query message opcode is not OP_QUERY.");
162+
}
163+
}
164+
156165
private void WriteOptionalFields(BsonBinaryWriter binaryWriter, BsonDocument fields)
157166
{
158167
if (fields != null)

src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ReplyMessageBinaryEncoder.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@
1616
using System;
1717
using System.Collections.Generic;
1818
using System.IO;
19-
using System.Linq;
20-
using System.Text;
21-
using System.Threading.Tasks;
2219
using MongoDB.Bson;
2320
using MongoDB.Bson.IO;
2421
using MongoDB.Bson.Serialization;
@@ -62,7 +59,8 @@ public ReplyMessage<TDocument> ReadMessage()
6259
stream.ReadInt32(); // messageSize
6360
var requestId = stream.ReadInt32();
6461
var responseTo = stream.ReadInt32();
65-
stream.ReadInt32(); // opcode
62+
var opcode = (Opcode)stream.ReadInt32();
63+
EnsureOpcodeIsValid(opcode);
6664
var flags = (ResponseFlags)stream.ReadInt32();
6765
var cursorId = stream.ReadInt64();
6866
var startingFrom = stream.ReadInt32();
@@ -158,6 +156,15 @@ public void WriteMessage(ReplyMessage<TDocument> message)
158156
stream.BackpatchSize(startPosition);
159157
}
160158

159+
// private methods
160+
private void EnsureOpcodeIsValid(Opcode opcode)
161+
{
162+
if (opcode != Opcode.Reply)
163+
{
164+
throw new FormatException("Reply message opcode is not OP_REPLY.");
165+
}
166+
}
167+
161168
// explicit interface implementations
162169
MongoDBMessage IMessageEncoder.ReadMessage()
163170
{

src/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/UpdateMessageBinaryEncoder.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@
1414
*/
1515

1616
using System;
17-
using System.Collections.Generic;
1817
using System.IO;
19-
using System.Linq;
20-
using System.Text;
21-
using System.Threading.Tasks;
2218
using MongoDB.Bson;
2319
using MongoDB.Bson.IO;
2420
using MongoDB.Bson.Serialization;
@@ -77,7 +73,8 @@ internal UpdateMessage ReadMessage<TDocument>(IBsonSerializer<TDocument> seriali
7773
stream.ReadInt32(); // messageSize
7874
var requestId = stream.ReadInt32();
7975
stream.ReadInt32(); // responseTo
80-
stream.ReadInt32(); // opcode
76+
var opcode = (Opcode)stream.ReadInt32();
77+
EnsureOpcodeIsValid(opcode);
8178
stream.ReadInt32(); // reserved
8279
var fullCollectionName = stream.ReadCString(Encoding);
8380
var flags = (UpdateFlags)stream.ReadInt32();
@@ -122,6 +119,15 @@ public void WriteMessage(UpdateMessage message)
122119
stream.BackpatchSize(startPosition);
123120
}
124121

122+
// private methods
123+
private void EnsureOpcodeIsValid(Opcode opcode)
124+
{
125+
if (opcode != Opcode.Update)
126+
{
127+
throw new FormatException("Update message opcode is not OP_UPDATE.");
128+
}
129+
}
130+
125131
private void WriteQuery(BsonBinaryWriter binaryWriter, BsonDocument query)
126132
{
127133
var context = BsonSerializationContext.CreateRoot(binaryWriter);

tests/MongoDB.Driver.Core.Tests/Core/WireProtocol/Messages/Encoders/BinaryEncoders/DeleteMessageBinaryEncoderTests.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@
1717
using System.IO;
1818
using FluentAssertions;
1919
using MongoDB.Bson;
20-
using MongoDB.Bson.IO;
21-
using MongoDB.Driver.Core.WireProtocol.Messages;
22-
using MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders;
2320
using Xunit;
2421

2522
namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders
@@ -105,6 +102,21 @@ public void ReadMessage_should_read_a_message()
105102
}
106103
}
107104

105+
[Fact]
106+
public void ReadMessage_should_throw_when_opcode_is_invalid()
107+
{
108+
var bytes = (byte[])__testMessageBytes.Clone();
109+
bytes[12]++;
110+
111+
using (var stream = new MemoryStream(bytes))
112+
{
113+
var subject = new DeleteMessageBinaryEncoder(stream, __messageEncoderSettings);
114+
var exception = Record.Exception(() => subject.ReadMessage());
115+
exception.Should().BeOfType<FormatException>();
116+
exception.Message.Should().Be("Delete message opcode is not OP_DELETE.");
117+
}
118+
}
119+
108120
[Theory]
109121
[InlineData(0, true)]
110122
[InlineData(1, false)]

tests/MongoDB.Driver.Core.Tests/Core/WireProtocol/Messages/Encoders/BinaryEncoders/GetMoreMessageBinaryEncoderTests.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@
1616
using System;
1717
using System.IO;
1818
using FluentAssertions;
19-
using MongoDB.Bson.IO;
20-
using MongoDB.Driver.Core.WireProtocol.Messages;
21-
using MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders;
2219
using Xunit;
2320

2421
namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders
@@ -86,6 +83,21 @@ public void ReadMessage_should_read_a_message()
8683
}
8784
}
8885

86+
[Fact]
87+
public void ReadMessage_should_throw_when_opcode_is_invalid()
88+
{
89+
var bytes = (byte[])__testMessageBytes.Clone();
90+
bytes[12]++;
91+
92+
using (var stream = new MemoryStream(bytes))
93+
{
94+
var subject = new GetMoreMessageBinaryEncoder(stream, __messageEncoderSettings);
95+
var exception = Record.Exception(() => subject.ReadMessage());
96+
exception.Should().BeOfType<FormatException>();
97+
exception.Message.Should().Be("GetMore message opcode is not OP_GET_MORE.");
98+
}
99+
}
100+
89101
[Fact]
90102
public void WriteMessage_should_throw_if_message_is_null()
91103
{

tests/MongoDB.Driver.Core.Tests/Core/WireProtocol/Messages/Encoders/BinaryEncoders/InsertMessageBinaryEncoderTests.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,9 @@
1818
using System.IO;
1919
using FluentAssertions;
2020
using MongoDB.Bson;
21-
using MongoDB.Bson.IO;
2221
using MongoDB.Bson.Serialization;
2322
using MongoDB.Bson.Serialization.Serializers;
2423
using MongoDB.Driver.Core.Misc;
25-
using MongoDB.Driver.Core.WireProtocol.Messages;
26-
using MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders;
2724
using Xunit;
2825

2926
namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders
@@ -126,6 +123,21 @@ public void ReadMessage_should_read_a_message()
126123
}
127124
}
128125

126+
[Fact]
127+
public void ReadMessage_should_throw_when_opcode_is_invalid()
128+
{
129+
var bytes = (byte[])__testMessageBytes.Clone();
130+
bytes[12]++;
131+
132+
using (var stream = new MemoryStream(bytes))
133+
{
134+
var subject = new InsertMessageBinaryEncoder<BsonDocument>(stream, __messageEncoderSettings, __serializer);
135+
var exception = Record.Exception(() => subject.ReadMessage());
136+
exception.Should().BeOfType<FormatException>();
137+
exception.Message.Should().Be("Insert message opcode is not OP_INSERT.");
138+
}
139+
}
140+
129141
[Theory]
130142
[InlineData(0, false)]
131143
[InlineData(1, true)]

0 commit comments

Comments
 (0)