diff options
author | Jason Rassi <rassi@10gen.com> | 2015-04-25 12:51:24 -0400 |
---|---|---|
committer | Jason Rassi <rassi@10gen.com> | 2015-04-28 16:53:26 -0400 |
commit | 659d6c26e12d3396aafff70ca11d74a4187b4084 (patch) | |
tree | 9bf68202e1e0745f4a9620a6e42e5adb7290c204 | |
parent | 5a1b51c847f9e4c466cecbbff0ac726152a69ee7 (diff) | |
download | mongo-659d6c26e12d3396aafff70ca11d74a4187b4084.tar.gz |
SERVER-18111 Forbid most user operations against "system.profile"
Forbids user writes to "system.profile". Notably, this also prevents
"system.profile" from being used as a source or target from
renameCollection.
Creation, drop, and capped conversion of "system.profile" remain
allowed.
(cherry picked from commit 5b80159eeb2332a5e8e79e30de27c2dd72c30a18)
-rw-r--r-- | jstests/core/system_profile.js | 60 | ||||
-rw-r--r-- | src/mongo/db/dbcommands.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/ops/insert.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/ops/insert.h | 11 |
4 files changed, 77 insertions, 4 deletions
diff --git a/jstests/core/system_profile.js b/jstests/core/system_profile.js new file mode 100644 index 00000000000..464044aaa1b --- /dev/null +++ b/jstests/core/system_profile.js @@ -0,0 +1,60 @@ +// Test various user operations against "system.profile" collection. SERVER-18111. + +var testDB = db.getSiblingDB("system_profile"); +var testDBCopy = db.getSiblingDB("system_profile_copy"); + +// Create/drop should succeed. +assert.commandWorked(testDB.dropDatabase()); +assert.commandWorked(testDB.createCollection("system.profile")); +testDB.system.profile.drop(); + +// convertToCapped should succeed. +assert.commandWorked(testDB.dropDatabase()); +assert.commandWorked(testDB.createCollection("system.profile")); +assert.eq(false, testDB.system.profile.stats().capped); +assert.commandWorked(testDB.system.profile.convertToCapped(1024 * 1024)); +assert.eq(true, testDB.system.profile.stats().capped); + +// Basic write operations should fail. +assert.commandWorked(testDB.dropDatabase()); +assert.commandWorked(testDB.createCollection("system.profile")); +assert.writeError(testDB.system.profile.insert({})); +assert.writeError(testDB.system.profile.update({}, {a: 1})); +assert.writeError(testDB.system.profile.update({}, {a: 1}, {upsert: true})); +assert.writeError(testDB.system.profile.remove({})); + +// Using mapReduce to write to "system.profile" should fail. +assert.commandWorked(testDB.dropDatabase()); +assert.writeOK(testDB.foo.insert({val: 1})); +assert.commandFailed(testDB.foo.runCommand("mapReduce", + {map: function() { emit(0, this.val); }, + reduce: function(id, values) { + return Array.sum(values); + }, + out: "system.profile"})); + +// Using aggregate to write to "system.profile" should fail. +assert.commandWorked(testDB.dropDatabase()); +assert.writeOK(testDB.foo.insert({val: 1})); +assert.commandFailed(testDB.foo.runCommand("aggregate", {pipeline: [{$out: "system.profile"}]})); + +// Renaming to/from "system.profile" should fail. +assert.commandWorked(testDB.dropDatabase()); +assert.commandWorked(testDB.createCollection("system.profile")); +assert.commandFailed(testDB.adminCommand({renameCollection: testDB.system.profile.getFullName(), + to: testDB.foo.getFullName()})); +assert.commandWorked(testDB.dropDatabase()); +assert.commandWorked(testDB.createCollection("foo")); +assert.commandFailed(testDB.adminCommand({renameCollection: testDB.foo.getFullName(), + to: testDB.system.profile.getFullName()})); + +// Copying a database containing "system.profile" should succeed. The "system.profile" collection +// should not be copied. +assert.commandWorked(testDB.dropDatabase()); +assert.commandWorked(testDB.createCollection("foo")); +assert.commandWorked(testDB.createCollection("system.profile")); +assert.commandWorked(testDBCopy.dropDatabase()); +assert.commandWorked(testDB.adminCommand({copydb: 1, fromdb: testDB.getName(), + todb: testDBCopy.getName()})); +assert.commandWorked(testDBCopy.foo.stats()); +assert.commandFailed(testDBCopy.system.profile.stats()); diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index 1c619bff82b..a9cb7c6e88b 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -583,7 +583,7 @@ namespace mongo { "must pass name of collection to create", firstElt.valuestrsafe()[0] != '\0'); - Status status = userAllowedWriteNS( dbname, firstElt.valuestr() ); + Status status = userAllowedCreateNS( dbname, firstElt.valuestr() ); if ( !status.isOK() ) { return appendCommandStatus( result, status ); } diff --git a/src/mongo/db/ops/insert.cpp b/src/mongo/db/ops/insert.cpp index 131ebbc67b7..707bdfd4792 100644 --- a/src/mongo/db/ops/insert.cpp +++ b/src/mongo/db/ops/insert.cpp @@ -141,6 +141,14 @@ namespace mongo { } Status userAllowedWriteNS( const StringData& db, const StringData& coll ) { + if ( coll == "system.profile" ) { + return Status( ErrorCodes::BadValue, + str::stream() << "cannot write to '" << db << ".system.profile'" ); + } + return userAllowedCreateNS( db, coll ); + } + + Status userAllowedCreateNS( const StringData& db, const StringData& coll ) { // validity checking if ( db.size() == 0 ) diff --git a/src/mongo/db/ops/insert.h b/src/mongo/db/ops/insert.h index cc3082c2f4b..b449bfb6301 100644 --- a/src/mongo/db/ops/insert.h +++ b/src/mongo/db/ops/insert.h @@ -41,12 +41,17 @@ namespace mongo { /** - * check if this is a collection _any_ user can write to - * does NOT to permission checking, that is elsewhere - * for example, can't write to foo.system.bar + * Returns Status::OK() if this namespace is valid for user write operations. If not, returns + * an error Status. */ Status userAllowedWriteNS( const StringData& db, const StringData& coll ); Status userAllowedWriteNS( const StringData& ns ); Status userAllowedWriteNS( const NamespaceString& ns ); + /** + * Returns Status::OK() if the namespace described by (db, coll) is valid for user create + * operations. If not, returns an error Status. + */ + Status userAllowedCreateNS( const StringData& db, const StringData& coll ); + } |