summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Boros <ian.boros@10gen.com>2019-01-10 18:57:38 -0500
committerIan Boros <ian.boros@10gen.com>2019-01-22 17:45:47 -0500
commit5c7c6729c37514760fd34da462b6961a2e385417 (patch)
treef22705f35cb925416965373d60e87163a5c4ce39
parent128c43eb4ab29a1477e51d6ff9ef1517df4376f6 (diff)
downloadmongo-5c7c6729c37514760fd34da462b6961a2e385417.tar.gz
SERVER-38275 ban explain with UUID
-rw-r--r--jstests/core/explain_uuid.js56
-rw-r--r--src/mongo/db/commands.cpp6
-rw-r--r--src/mongo/db/commands/count_cmd.cpp2
-rw-r--r--src/mongo/db/commands/find_cmd.cpp2
-rw-r--r--src/mongo/idl/idl_parser.cpp6
5 files changed, 70 insertions, 2 deletions
diff --git a/jstests/core/explain_uuid.js b/jstests/core/explain_uuid.js
new file mode 100644
index 00000000000..a7de30a1ef2
--- /dev/null
+++ b/jstests/core/explain_uuid.js
@@ -0,0 +1,56 @@
+/**
+ * Test that running explain() providing a collection UUID rather than collection name will fail
+ * cleanly.
+ */
+(function() {
+ "use strict";
+
+ // Use our own database so that we're guaranteed the only collection is this one.
+ const explainDB = db.getSiblingDB("explain_uuid_db");
+
+ assert.commandWorked(explainDB.dropDatabase());
+
+ const coll = explainDB.explain_uuid;
+ assert.writeOK(coll.insert({a: 1}));
+
+ const collInfos = explainDB.getCollectionInfos({name: coll.getName()});
+ assert.eq(collInfos.length, 1, collInfos);
+ const uuid = collInfos[0].info.uuid;
+
+ // Run a find explain looking up by UUID.
+ assert.commandFailedWithCode(explainDB.runCommand({explain: {find: uuid}}),
+ ErrorCodes.InvalidNamespace);
+
+ // Do similar for other commands.
+ assert.commandFailedWithCode(explainDB.runCommand({explain: {aggregate: uuid, cursor: {}}}),
+ ErrorCodes.TypeMismatch);
+
+ assert.commandFailedWithCode(explainDB.runCommand({explain: {count: uuid}}),
+ ErrorCodes.InvalidNamespace);
+
+ assert.commandFailedWithCode(explainDB.runCommand({explain: {distinct: uuid, key: "x"}}),
+ ErrorCodes.InvalidNamespace);
+
+ // When auth is enabled, running findAndModify with an invalid namespace will produce a special
+ // error during the auth check, rather than the generic 'InvalidNamespace' error.
+ const expectedCode = TestData.auth ? 17137 : ErrorCodes.InvalidNamespace;
+ assert.commandFailedWithCode(
+ explainDB.runCommand({explain: {findAndModify: uuid, query: {a: 1}, remove: true}}),
+ expectedCode);
+
+ assert.commandFailedWithCode(
+ explainDB.runCommand({explain: {delete: uuid, deletes: [{q: {}, limit: 1}]}}),
+ ErrorCodes.BadValue);
+
+ assert.commandFailedWithCode(explainDB.runCommand({
+ explain: {
+ update: uuid,
+ updates: [{
+ q: {a: 1},
+ u: {$set: {b: 1}},
+ }]
+ }
+ }),
+ ErrorCodes.BadValue);
+
+})();
diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp
index 4ff86edc586..f7aa71e9184 100644
--- a/src/mongo/db/commands.cpp
+++ b/src/mongo/db/commands.cpp
@@ -126,6 +126,12 @@ NamespaceString Command::parseNsCollectionRequired(const string& dbname, const B
// Accepts both BSON String and Symbol for collection name per SERVER-16260
// TODO(kangas) remove Symbol support in MongoDB 3.0 after Ruby driver audit
BSONElement first = cmdObj.firstElement();
+ const bool isUUID = (first.canonicalType() == canonicalizeBSONType(mongo::BinData) &&
+ first.binDataType() == BinDataType::newUUID);
+ uassert(ErrorCodes::InvalidNamespace,
+ str::stream() << "Collection name must be provided. UUID is not valid in this "
+ << "context",
+ !isUUID);
uassert(ErrorCodes::InvalidNamespace,
str::stream() << "collection name has invalid type " << typeName(first.type()),
first.canonicalType() == canonicalizeBSONType(mongo::String));
diff --git a/src/mongo/db/commands/count_cmd.cpp b/src/mongo/db/commands/count_cmd.cpp
index f8af43deaf4..2a306facb7a 100644
--- a/src/mongo/db/commands/count_cmd.cpp
+++ b/src/mongo/db/commands/count_cmd.cpp
@@ -118,7 +118,7 @@ public:
BSONObjBuilder* out) const {
const bool isExplain = true;
Lock::DBLock dbLock(opCtx, dbname, MODE_IS);
- auto nss = parseNsOrUUID(opCtx, dbname, cmdObj);
+ auto nss = parseNsCollectionRequired(dbname, cmdObj);
auto request = CountRequest::parseFromBSON(nss, cmdObj, isExplain);
if (!request.isOK()) {
return request.getStatus();
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp
index c50f5a93e80..c913dde609e 100644
--- a/src/mongo/db/commands/find_cmd.cpp
+++ b/src/mongo/db/commands/find_cmd.cpp
@@ -133,7 +133,7 @@ public:
const BSONObj& cmdObj,
ExplainOptions::Verbosity verbosity,
BSONObjBuilder* out) const override {
- const NamespaceString nss(parseNs(dbname, cmdObj));
+ const NamespaceString nss(parseNsCollectionRequired(dbname, cmdObj));
if (!nss.isValid()) {
return {ErrorCodes::InvalidNamespace,
str::stream() << "Invalid collection name: " << nss.ns()};
diff --git a/src/mongo/idl/idl_parser.cpp b/src/mongo/idl/idl_parser.cpp
index 9d4c139c9dc..fbcd93b5e4f 100644
--- a/src/mongo/idl/idl_parser.cpp
+++ b/src/mongo/idl/idl_parser.cpp
@@ -227,6 +227,12 @@ void IDLParserErrorContext::throwBadEnumValue(StringData enumValue) const {
NamespaceString IDLParserErrorContext::parseNSCollectionRequired(StringData dbName,
const BSONElement& element) {
+ const bool isUUID = (element.canonicalType() == canonicalizeBSONType(mongo::BinData) &&
+ element.binDataType() == BinDataType::newUUID);
+ uassert(ErrorCodes::BadValue,
+ str::stream() << "Collection name must be provided. UUID is not valid in this "
+ << "context",
+ !isUUID);
uassert(ErrorCodes::BadValue,
str::stream() << "collection name has invalid type " << typeName(element.type()),
element.canonicalType() == canonicalizeBSONType(mongo::String));