summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Guo <robert.guo@10gen.com>2016-03-22 17:10:50 -0400
committerRobert Guo <robert.guo@10gen.com>2016-03-29 13:08:43 -0400
commite242b49373f0a9ee39f2b02f1a766a84c2c869b6 (patch)
tree3eaf08b0a85cbfde4b041f944001232d5e55e6e6
parentea07e34466f14b127ac97f58ec6a40e9e52ebbd5 (diff)
downloadmongo-e242b49373f0a9ee39f2b02f1a766a84c2c869b6.tar.gz
SERVER-22577 disallow creation of databases containing $ on mmapv1
-rw-r--r--src/mongo/client/dbclient.cpp2
-rw-r--r--src/mongo/db/auth/privilege_parser.cpp4
-rw-r--r--src/mongo/db/auth/role_graph_builtin_roles.cpp4
-rw-r--r--src/mongo/db/auth/user_document_parser.cpp3
-rw-r--r--src/mongo/db/catalog/database_holder.cpp4
-rw-r--r--src/mongo/db/commands/copydb.cpp2
-rw-r--r--src/mongo/db/namespace_string-inl.h6
-rw-r--r--src/mongo/db/namespace_string.h25
-rw-r--r--src/mongo/db/namespace_string_test.cpp31
-rw-r--r--src/mongo/db/ops/insert.cpp2
-rw-r--r--src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp3
-rw-r--r--src/mongo/rpc/command_request.cpp7
-rw-r--r--src/mongo/rpc/legacy_request.cpp7
-rw-r--r--src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp2
-rw-r--r--src/mongo/s/commands/commands_public.cpp2
-rw-r--r--src/mongo/scripting/mozjs/db.cpp2
16 files changed, 82 insertions, 24 deletions
diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp
index c682b1684b2..073c26f6d16 100644
--- a/src/mongo/client/dbclient.cpp
+++ b/src/mongo/client/dbclient.cpp
@@ -291,7 +291,7 @@ rpc::UniqueReply DBClientWithCommands::runCommandWithMetadata(StringData databas
const BSONObj& commandArgs) {
uassert(ErrorCodes::InvalidNamespace,
str::stream() << "Database name '" << database << "' is not valid.",
- NamespaceString::validDBName(database));
+ NamespaceString::validDBName(database, NamespaceString::DollarInDbNameBehavior::Allow));
// call() oddly takes this by pointer, so we need to put it on the stack.
auto host = getServerAddress();
diff --git a/src/mongo/db/auth/privilege_parser.cpp b/src/mongo/db/auth/privilege_parser.cpp
index fab88307862..e9781c818bc 100644
--- a/src/mongo/db/auth/privilege_parser.cpp
+++ b/src/mongo/db/auth/privilege_parser.cpp
@@ -87,7 +87,9 @@ bool ParsedResource::isValid(std::string* errMsg) const {
*errMsg = stream() << cluster.name() << " must be true when specified";
return false;
}
- if (isDbSet() && (!NamespaceString::validDBName(getDb()) && !getDb().empty())) {
+ if (isDbSet() &&
+ (!NamespaceString::validDBName(getDb(), NamespaceString::DollarInDbNameBehavior::Allow) &&
+ !getDb().empty())) {
*errMsg = stream() << getDb() << " is not a valid database name";
return false;
}
diff --git a/src/mongo/db/auth/role_graph_builtin_roles.cpp b/src/mongo/db/auth/role_graph_builtin_roles.cpp
index 923aa1c40e3..ddad1248be8 100644
--- a/src/mongo/db/auth/role_graph_builtin_roles.cpp
+++ b/src/mongo/db/auth/role_graph_builtin_roles.cpp
@@ -622,7 +622,9 @@ void RoleGraph::generateUniversalPrivileges(PrivilegeVector* privileges) {
}
bool RoleGraph::isBuiltinRole(const RoleName& role) {
- if (!NamespaceString::validDBName(role.getDB()) || role.getDB() == "$external") {
+ if (!NamespaceString::validDBName(role.getDB(),
+ NamespaceString::DollarInDbNameBehavior::Allow) ||
+ role.getDB() == "$external") {
return false;
}
diff --git a/src/mongo/db/auth/user_document_parser.cpp b/src/mongo/db/auth/user_document_parser.cpp
index 08b0ebb7a0f..234f3b64d73 100644
--- a/src/mongo/db/auth/user_document_parser.cpp
+++ b/src/mongo/db/auth/user_document_parser.cpp
@@ -238,7 +238,8 @@ Status V2UserDocumentParser::checkValidUserDocument(const BSONObj& doc) const {
return _badValue("User document needs 'db' field to be a non-empty string", 0);
}
StringData userDBStr = userDBElement.valueStringData();
- if (!NamespaceString::validDBName(userDBStr) && userDBStr != "$external") {
+ if (!NamespaceString::validDBName(userDBStr, NamespaceString::DollarInDbNameBehavior::Allow) &&
+ userDBStr != "$external") {
return _badValue(mongoutils::str::stream() << "'" << userDBStr
<< "' is not a valid value for the db field.",
0);
diff --git a/src/mongo/db/catalog/database_holder.cpp b/src/mongo/db/catalog/database_holder.cpp
index f4a2cf62970..7ba373fd362 100644
--- a/src/mongo/db/catalog/database_holder.cpp
+++ b/src/mongo/db/catalog/database_holder.cpp
@@ -62,7 +62,9 @@ StringData _todb(StringData ns) {
uassert(13075, "db name can't be empty", i > 0);
const StringData d = ns.substr(0, i);
- uassert(13280, "invalid db name: " + ns.toString(), NamespaceString::validDBName(d));
+ uassert(13280,
+ "invalid db name: " + ns.toString(),
+ NamespaceString::validDBName(d, NamespaceString::DollarInDbNameBehavior::Allow));
return d;
}
diff --git a/src/mongo/db/commands/copydb.cpp b/src/mongo/db/commands/copydb.cpp
index 75d5aa4e6dd..a0ad9c46d81 100644
--- a/src/mongo/db/commands/copydb.cpp
+++ b/src/mongo/db/commands/copydb.cpp
@@ -144,7 +144,7 @@ public:
return false;
}
- if (!NamespaceString::validDBName(todb)) {
+ if (!NamespaceString::validDBName(todb, NamespaceString::DollarInDbNameBehavior::Allow)) {
errmsg = "invalid todb name: " + todb;
return false;
}
diff --git a/src/mongo/db/namespace_string-inl.h b/src/mongo/db/namespace_string-inl.h
index 8e8808fb9b8..7bb98f81086 100644
--- a/src/mongo/db/namespace_string-inl.h
+++ b/src/mongo/db/namespace_string-inl.h
@@ -54,7 +54,7 @@ inline bool NamespaceString::special(StringData ns) {
return !normal(ns) || ns.substr(ns.find('.')).startsWith(".system.");
}
-inline bool NamespaceString::validDBName(StringData db) {
+inline bool NamespaceString::validDBName(StringData db, DollarInDbNameBehavior behavior) {
if (db.size() == 0 || db.size() > 64)
return false;
@@ -67,6 +67,10 @@ inline bool NamespaceString::validDBName(StringData db) {
case ' ':
case '"':
return false;
+ case '$':
+ if (behavior == DollarInDbNameBehavior::Disallow)
+ return false;
+ continue;
#ifdef _WIN32
// We prohibit all FAT32-disallowed characters on Windows
case '*':
diff --git a/src/mongo/db/namespace_string.h b/src/mongo/db/namespace_string.h
index 5a891df19c0..65d23736dee 100644
--- a/src/mongo/db/namespace_string.h
+++ b/src/mongo/db/namespace_string.h
@@ -96,6 +96,16 @@ public:
MaxNsCollectionLen = MaxNsLen - 7 /*strlen(".$extra")*/,
};
+ /**
+ * DollarInDbNameBehavior::allow is deprecated.
+ * Please use DollarInDbNameBehavior::disallow and check explicitly for any DB names that must
+ * contain a $.
+ */
+ enum class DollarInDbNameBehavior {
+ Disallow,
+ Allow, // Deprecated
+ };
+
StringData db() const;
StringData coll() const;
@@ -165,7 +175,7 @@ public:
* valid.
*/
bool isValid() const {
- return validDBName(db()) && !coll().empty();
+ return validDBName(db(), DollarInDbNameBehavior::Allow) && !coll().empty();
}
bool operator==(const std::string& nsIn) const {
@@ -220,12 +230,12 @@ public:
/**
* Returns true for DBs with special meaning to mongodb.
*/
- static bool internalDb(StringData ns) {
- if (ns == "admin")
+ static bool internalDb(StringData db) {
+ if (db == "admin")
return true;
- if (ns == "local")
+ if (db == "local")
return true;
- if (ns == "config")
+ if (db == "config")
return true;
return false;
}
@@ -242,9 +252,12 @@ public:
* foo"bar
*
* @param db - a possible database name
+ * @param DollarInDbNameBehavior - please do not change the default value. DB names that must
+ * contain a $ should be checked explicitly.
* @return if db is an allowed database name
*/
- static bool validDBName(StringData dbin);
+ static bool validDBName(StringData db,
+ DollarInDbNameBehavior behavior = DollarInDbNameBehavior::Disallow);
/**
* Takes a fully qualified namespace (ie dbname.collectionName), and returns true if
diff --git a/src/mongo/db/namespace_string_test.cpp b/src/mongo/db/namespace_string_test.cpp
index ba85cc775e3..03e2837159c 100644
--- a/src/mongo/db/namespace_string_test.cpp
+++ b/src/mongo/db/namespace_string_test.cpp
@@ -66,11 +66,40 @@ TEST(NamespaceStringTest, Special) {
}
TEST(NamespaceStringTest, DatabaseValidNames) {
+ ASSERT(NamespaceString::validDBName("foo", NamespaceString::DollarInDbNameBehavior::Allow));
+ ASSERT(NamespaceString::validDBName("foo$bar", NamespaceString::DollarInDbNameBehavior::Allow));
+ ASSERT(
+ !NamespaceString::validDBName("foo/bar", NamespaceString::DollarInDbNameBehavior::Allow));
+ ASSERT(
+ !NamespaceString::validDBName("foo bar", NamespaceString::DollarInDbNameBehavior::Allow));
+ ASSERT(
+ !NamespaceString::validDBName("foo.bar", NamespaceString::DollarInDbNameBehavior::Allow));
+ ASSERT(
+ !NamespaceString::validDBName("foo\\bar", NamespaceString::DollarInDbNameBehavior::Allow));
+ ASSERT(
+ !NamespaceString::validDBName("foo\"bar", NamespaceString::DollarInDbNameBehavior::Allow));
+ ASSERT(!NamespaceString::validDBName(StringData("a\0b", StringData::LiteralTag()),
+ NamespaceString::DollarInDbNameBehavior::Allow));
+#ifdef _WIN32
+ ASSERT(
+ !NamespaceString::validDBName("foo*bar", NamespaceString::DollarInDbNameBehavior::Allow));
+ ASSERT(
+ !NamespaceString::validDBName("foo<bar", NamespaceString::DollarInDbNameBehavior::Allow));
+ ASSERT(
+ !NamespaceString::validDBName("foo>bar", NamespaceString::DollarInDbNameBehavior::Allow));
+ ASSERT(
+ !NamespaceString::validDBName("foo:bar", NamespaceString::DollarInDbNameBehavior::Allow));
+ ASSERT(
+ !NamespaceString::validDBName("foo|bar", NamespaceString::DollarInDbNameBehavior::Allow));
+ ASSERT(
+ !NamespaceString::validDBName("foo?bar", NamespaceString::DollarInDbNameBehavior::Allow));
+#endif
+
ASSERT(NamespaceString::validDBName("foo"));
+ ASSERT(!NamespaceString::validDBName("foo$bar"));
ASSERT(!NamespaceString::validDBName("foo/bar"));
ASSERT(!NamespaceString::validDBName("foo bar"));
ASSERT(!NamespaceString::validDBName("foo.bar"));
- ASSERT(!NamespaceString::validDBName("foo.bar"));
ASSERT(!NamespaceString::validDBName("foo\\bar"));
ASSERT(!NamespaceString::validDBName("foo\"bar"));
ASSERT(!NamespaceString::validDBName(StringData("a\0b", StringData::LiteralTag())));
diff --git a/src/mongo/db/ops/insert.cpp b/src/mongo/db/ops/insert.cpp
index 23d3d1bacce..7086d79707d 100644
--- a/src/mongo/db/ops/insert.cpp
+++ b/src/mongo/db/ops/insert.cpp
@@ -151,7 +151,7 @@ Status userAllowedCreateNS(StringData db, StringData coll) {
if (db.size() == 0)
return Status(ErrorCodes::BadValue, "db cannot be blank");
- if (!NamespaceString::validDBName(db))
+ if (!NamespaceString::validDBName(db, NamespaceString::DollarInDbNameBehavior::Allow))
return Status(ErrorCodes::BadValue, "invalid db name");
if (coll.size() == 0)
diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp
index 306a8e26b67..d14297ef9af 100644
--- a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp
+++ b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp
@@ -162,6 +162,9 @@ MMAPV1DatabaseCatalogEntry::MMAPV1DatabaseCatalogEntry(OperationContext* txn,
_path(path.toString()),
_namespaceIndex(_path, name.toString()),
_extentManager(std::move(extentManager)) {
+ massert(34469,
+ str::stream() << name << " is not a valid database name",
+ NamespaceString::validDBName(name));
invariant(txn->lockState()->isDbLockedForMode(name, MODE_X));
try {
diff --git a/src/mongo/rpc/command_request.cpp b/src/mongo/rpc/command_request.cpp
index ad9316b1c4d..e8655158099 100644
--- a/src/mongo/rpc/command_request.cpp
+++ b/src/mongo/rpc/command_request.cpp
@@ -78,9 +78,10 @@ CommandRequest::CommandRequest(const Message* message) : _message(message) {
<< " bytes. Got: " << _database,
(_database.size() >= kMinDatabaseLength) && (_database.size() <= kMaxDatabaseLength));
- uassert(ErrorCodes::InvalidNamespace,
- str::stream() << "Invalid database name: '" << _database << "'",
- NamespaceString::validDBName(_database));
+ uassert(
+ ErrorCodes::InvalidNamespace,
+ str::stream() << "Invalid database name: '" << _database << "'",
+ NamespaceString::validDBName(_database, NamespaceString::DollarInDbNameBehavior::Allow));
uassertStatusOK(cur.readAndAdvance<>(&str));
_commandName = std::move(str.value);
diff --git a/src/mongo/rpc/legacy_request.cpp b/src/mongo/rpc/legacy_request.cpp
index d0340b0b831..f9b7fe41c77 100644
--- a/src/mongo/rpc/legacy_request.cpp
+++ b/src/mongo/rpc/legacy_request.cpp
@@ -42,9 +42,10 @@ LegacyRequest::LegacyRequest(const Message* message)
: _message(std::move(message)), _dbMessage(*message), _queryMessage(_dbMessage) {
_database = nsToDatabaseSubstring(_queryMessage.ns);
- uassert(ErrorCodes::InvalidNamespace,
- str::stream() << "Invalid database name: '" << _database << "'",
- NamespaceString::validDBName(_database));
+ uassert(
+ ErrorCodes::InvalidNamespace,
+ str::stream() << "Invalid database name: '" << _database << "'",
+ NamespaceString::validDBName(_database, NamespaceString::DollarInDbNameBehavior::Allow));
std::tie(_upconvertedCommandArgs, _upconvertedMetadata) =
uassertStatusOK(rpc::upconvertRequestMetadata(std::move(_queryMessage.query),
diff --git a/src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp b/src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp
index 010abb02a69..7934cffb8ab 100644
--- a/src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp
+++ b/src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp
@@ -332,7 +332,7 @@ StatusWith<ShardDrainingStatus> CatalogManagerReplicaSet::removeShard(OperationC
StatusWith<OpTimePair<DatabaseType>> CatalogManagerReplicaSet::getDatabase(
OperationContext* txn, const std::string& dbName) {
- if (!NamespaceString::validDBName(dbName)) {
+ if (!NamespaceString::validDBName(dbName, NamespaceString::DollarInDbNameBehavior::Allow)) {
return {ErrorCodes::InvalidNamespace, stream() << dbName << " is not a valid db name"};
}
diff --git a/src/mongo/s/commands/commands_public.cpp b/src/mongo/s/commands/commands_public.cpp
index 12279397501..861cc4a9a17 100644
--- a/src/mongo/s/commands/commands_public.cpp
+++ b/src/mongo/s/commands/commands_public.cpp
@@ -563,7 +563,7 @@ public:
uassert(ErrorCodes::EmptyFieldName, "missing todb argument", !todb.empty());
uassert(ErrorCodes::InvalidNamespace,
"invalid todb argument",
- NamespaceString::validDBName(todb));
+ NamespaceString::validDBName(todb, NamespaceString::DollarInDbNameBehavior::Allow));
auto confTo = uassertStatusOK(grid.implicitCreateDb(txn, todb));
uassert(ErrorCodes::IllegalOperation,
diff --git a/src/mongo/scripting/mozjs/db.cpp b/src/mongo/scripting/mozjs/db.cpp
index 97112595037..565cf20cb1c 100644
--- a/src/mongo/scripting/mozjs/db.cpp
+++ b/src/mongo/scripting/mozjs/db.cpp
@@ -135,7 +135,7 @@ void DBInfo::construct(JSContext* cx, JS::CallArgs args) {
std::string dbName = ValueWriter(cx, args.get(1)).toString();
- if (!NamespaceString::validDBName(dbName))
+ if (!NamespaceString::validDBName(dbName, NamespaceString::DollarInDbNameBehavior::Allow))
uasserted(ErrorCodes::BadValue,
str::stream() << "[" << dbName << "] is not a valid database name");