summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Rassi <rassi@10gen.com>2015-04-25 12:51:24 -0400
committerJason Rassi <rassi@10gen.com>2015-04-28 16:53:26 -0400
commit659d6c26e12d3396aafff70ca11d74a4187b4084 (patch)
tree9bf68202e1e0745f4a9620a6e42e5adb7290c204
parent5a1b51c847f9e4c466cecbbff0ac726152a69ee7 (diff)
downloadmongo-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.js60
-rw-r--r--src/mongo/db/dbcommands.cpp2
-rw-r--r--src/mongo/db/ops/insert.cpp8
-rw-r--r--src/mongo/db/ops/insert.h11
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 );
+
}