diff options
author | Robert Guo <robert.guo@10gen.com> | 2016-03-22 17:10:50 -0400 |
---|---|---|
committer | Robert Guo <robert.guo@10gen.com> | 2016-03-29 13:08:43 -0400 |
commit | e242b49373f0a9ee39f2b02f1a766a84c2c869b6 (patch) | |
tree | 3eaf08b0a85cbfde4b041f944001232d5e55e6e6 /src/mongo | |
parent | ea07e34466f14b127ac97f58ec6a40e9e52ebbd5 (diff) | |
download | mongo-e242b49373f0a9ee39f2b02f1a766a84c2c869b6.tar.gz |
SERVER-22577 disallow creation of databases containing $ on mmapv1
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/client/dbclient.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/auth/privilege_parser.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/auth/role_graph_builtin_roles.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/auth/user_document_parser.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/catalog/database_holder.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/commands/copydb.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/namespace_string-inl.h | 6 | ||||
-rw-r--r-- | src/mongo/db/namespace_string.h | 25 | ||||
-rw-r--r-- | src/mongo/db/namespace_string_test.cpp | 31 | ||||
-rw-r--r-- | src/mongo/db/ops/insert.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp | 3 | ||||
-rw-r--r-- | src/mongo/rpc/command_request.cpp | 7 | ||||
-rw-r--r-- | src/mongo/rpc/legacy_request.cpp | 7 | ||||
-rw-r--r-- | src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp | 2 | ||||
-rw-r--r-- | src/mongo/s/commands/commands_public.cpp | 2 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/db.cpp | 2 |
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"); |