summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdam Midvidy <amidvidy@gmail.com>2015-08-02 16:46:16 -0400
committerAdam Midvidy <amidvidy@gmail.com>2015-08-05 11:05:32 -0400
commit18808cd923789a34abd7f13d62e7a73fafd5ce5f (patch)
tree81b58c1f98a005cfbdd0f9ac1128fdefcebb71b4 /src
parent197ea2a625dc04d95a7ad4933283b5f02ca2ad9e (diff)
downloadmongo-18808cd923789a34abd7f13d62e7a73fafd5ce5f.tar.gz
SERVER-19711 detect invalid wrapped queries in ServerSelectionMetadata upconversion
Diffstat (limited to 'src')
-rw-r--r--src/mongo/rpc/metadata/server_selection_metadata.cpp30
-rw-r--r--src/mongo/rpc/metadata/server_selection_metadata_test.cpp10
2 files changed, 32 insertions, 8 deletions
diff --git a/src/mongo/rpc/metadata/server_selection_metadata.cpp b/src/mongo/rpc/metadata/server_selection_metadata.cpp
index 1441243a4e7..a4fbbde3fca 100644
--- a/src/mongo/rpc/metadata/server_selection_metadata.cpp
+++ b/src/mongo/rpc/metadata/server_selection_metadata.cpp
@@ -55,17 +55,26 @@ const char kQueryWrapper[] = "query";
/**
* Utility to unwrap a '$query' or 'query' wrapped command object. The first element of the
- * return value indicates whether the command was unwrapped, and the second element is either
+ * returned tuple indicates whether the command was unwrapped, and the second element is either
* the unwrapped command (if it was wrapped), or the original command if it was not.
*/
-std::tuple<bool, BSONObj> unwrapCommand(const BSONObj& maybeWrapped) {
+StatusWith<std::tuple<bool, BSONObj>> unwrapCommand(const BSONObj& maybeWrapped) {
const auto firstElFieldName = maybeWrapped.firstElementFieldName();
- if ((firstElFieldName == StringData(kDollarQueryWrapper)) ||
- (firstElFieldName == StringData(kQueryWrapper))) {
- // TODO: do we need getOwned here?
- return std::make_tuple(true, maybeWrapped.firstElement().embeddedObject());
+
+ if ((firstElFieldName != StringData(kDollarQueryWrapper)) &&
+ (firstElFieldName != StringData(kQueryWrapper))) {
+ return std::make_tuple(false, maybeWrapped);
+ }
+
+ BSONElement inner;
+ auto extractStatus =
+ bsonExtractTypedField(maybeWrapped, firstElFieldName, mongo::Object, &inner);
+
+ if (!extractStatus.isOK()) {
+ return extractStatus;
}
- return std::make_tuple(false, maybeWrapped);
+
+ return std::make_tuple(true, inner.Obj());
}
/**
@@ -215,9 +224,14 @@ Status ServerSelectionMetadata::upconvert(const BSONObj& legacyCommand,
// First we need to check if we have a wrapped command. That is, a command of the form
// {'$query': { 'commandName': 1, ...}, '$someOption': 5, ....}. Curiously, the field name
// of the wrapped query can be either '$query', or 'query'.
+ auto swUnwrapped = unwrapCommand(legacyCommand);
+ if (!swUnwrapped.isOK()) {
+ return swUnwrapped.getStatus();
+ }
+
BSONObj maybeUnwrapped;
bool wasWrapped;
- std::tie(wasWrapped, maybeUnwrapped) = unwrapCommand(legacyCommand);
+ std::tie(wasWrapped, maybeUnwrapped) = swUnwrapped.getValue();
if (wasWrapped) {
// Check if legacyCommand has an invalid $maxTimeMS option.
diff --git a/src/mongo/rpc/metadata/server_selection_metadata_test.cpp b/src/mongo/rpc/metadata/server_selection_metadata_test.cpp
index ae8d4057b45..40e7aebae58 100644
--- a/src/mongo/rpc/metadata/server_selection_metadata_test.cpp
+++ b/src/mongo/rpc/metadata/server_selection_metadata_test.cpp
@@ -177,6 +177,16 @@ TEST(ServerSelectionMetadata, UpconvertInvalidMetadata) {
<< "pong"
<< "$queryOptions" << BSONObj()),
ErrorCodes::NoSuchKey);
+
+ // invalid wrapped query
+ checkUpconvertFails(BSON("$query" << 1), ErrorCodes::TypeMismatch);
+ checkUpconvertFails(BSON("$query"
+ << ""),
+ ErrorCodes::TypeMismatch);
+ checkUpconvertFails(BSON("query" << 1), ErrorCodes::TypeMismatch);
+ checkUpconvertFails(BSON("query"
+ << ""),
+ ErrorCodes::TypeMismatch);
}
} // namespace