summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Chelminski <adam.chelminski@mongodb.com>2016-08-17 17:11:10 -0400
committerAdam Chelminski <adam.chelminski@mongodb.com>2016-08-19 11:11:23 -0400
commit1a3d60af4d27d72e15637bb43510fe1b592a6c43 (patch)
tree7ab2edd2291f41a2fe37262f32e37618de5f0388
parent76f1c8254147f806fef11e9dedabee359422c02b (diff)
downloadmongo-1a3d60af4d27d72e15637bb43510fe1b592a6c43.tar.gz
SERVER-13517 Internal client validates BSON in all command responses and when reading from cursor in DBClientCursor
-rw-r--r--src/mongo/client/dbclientcursor.cpp14
-rw-r--r--src/mongo/client/dbclientcursor.h1
-rw-r--r--src/mongo/db/dbmessage.h4
-rw-r--r--src/mongo/rpc/legacy_reply.cpp10
-rw-r--r--src/mongo/rpc/legacy_reply.h2
5 files changed, 28 insertions, 3 deletions
diff --git a/src/mongo/client/dbclientcursor.cpp b/src/mongo/client/dbclientcursor.cpp
index 2c48dbce514..2b534defbba 100644
--- a/src/mongo/client/dbclientcursor.cpp
+++ b/src/mongo/client/dbclientcursor.cpp
@@ -264,6 +264,7 @@ void DBClientCursor::commandDataReceived() {
QueryResult::View qr = batch.m.singleData().view2ptr();
batch.data = qr.data();
+ batch.remainingBytes = qr.dataLen();
}
void DBClientCursor::dataReceived(bool& retry, string& host) {
@@ -302,6 +303,7 @@ void DBClientCursor::dataReceived(bool& retry, string& host) {
batch.nReturned = qr.getNReturned();
batch.pos = 0;
batch.data = qr.data();
+ batch.remainingBytes = qr.dataLen();
_client->checkResponse(batch.data, batch.nReturned, &retry, &host); // watches for "not master"
@@ -344,9 +346,19 @@ BSONObj DBClientCursor::next() {
uassert(13422, "DBClientCursor next() called but more() is false", batch.pos < batch.nReturned);
- batch.pos++;
+ uassert(ErrorCodes::InvalidBSON,
+ "Got invalid BSON from external server while reading from cursor.",
+ validateBSON(batch.data,
+ batch.remainingBytes,
+ enableBSON1_1 ? BSONVersion::kV1_1 : BSONVersion::kV1_0)
+ .isOK());
+
BSONObj o(batch.data);
+
+ batch.pos++;
batch.data += o.objsize();
+ batch.remainingBytes -= o.objsize();
+
/* todo would be good to make data null at end of batch for safety */
return o;
}
diff --git a/src/mongo/client/dbclientcursor.h b/src/mongo/client/dbclientcursor.h
index b8592738921..c0367b830a0 100644
--- a/src/mongo/client/dbclientcursor.h
+++ b/src/mongo/client/dbclientcursor.h
@@ -212,6 +212,7 @@ public:
int nReturned{0};
int pos{0};
const char* data{nullptr};
+ int remainingBytes{0};
public:
Batch() = default;
diff --git a/src/mongo/db/dbmessage.h b/src/mongo/db/dbmessage.h
index 7fabf117421..01530edd641 100644
--- a/src/mongo/db/dbmessage.h
+++ b/src/mongo/db/dbmessage.h
@@ -138,6 +138,10 @@ public:
return storage().view(sizeof(Layout));
}
+ int32_t dataLen() const {
+ return msgdata().getLen() - sizeof(Layout);
+ }
+
protected:
const ConstDataView& storage() const {
return _storage;
diff --git a/src/mongo/rpc/legacy_reply.cpp b/src/mongo/rpc/legacy_reply.cpp
index e9af23dee9e..572a96d2dd2 100644
--- a/src/mongo/rpc/legacy_reply.cpp
+++ b/src/mongo/rpc/legacy_reply.cpp
@@ -33,6 +33,7 @@
#include <tuple>
#include <utility>
+#include "mongo/bson/bson_validate.h"
#include "mongo/rpc/legacy_reply_builder.h"
#include "mongo/rpc/metadata.h"
#include "mongo/util/assert_util.h"
@@ -67,6 +68,15 @@ LegacyReply::LegacyReply(const Message* message) : _message(std::move(message))
<< qr.getStartingFrom(),
qr.getStartingFrom() == 0);
+ if (serverGlobalParams.objcheck) {
+ uassert(ErrorCodes::InvalidBSON,
+ "Got legacy command reply with invalid BSON in the metadata field.",
+ validateBSON(qr.data(),
+ qr.dataLen(),
+ enableBSON1_1 ? BSONVersion::kV1_1 : BSONVersion::kV1_0)
+ .isOK());
+ }
+
std::tie(_commandReply, _metadata) =
uassertStatusOK(rpc::upconvertReplyMetadata(BSONObj(qr.data())));
diff --git a/src/mongo/rpc/legacy_reply.h b/src/mongo/rpc/legacy_reply.h
index bfb366f1da2..7d3d222f59d 100644
--- a/src/mongo/rpc/legacy_reply.h
+++ b/src/mongo/rpc/legacy_reply.h
@@ -41,8 +41,6 @@ namespace rpc {
/**
* Immutable view of an OP_REPLY legacy-style command reply.
- *
- * TODO: BSON validation (SERVER-18167)
*/
class LegacyReply : public ReplyInterface {
public: