diff options
author | Benety Goh <benety@mongodb.com> | 2014-09-24 15:08:54 -0400 |
---|---|---|
committer | Benety Goh <benety@mongodb.com> | 2014-09-25 11:15:45 -0400 |
commit | 05c6ae595922a89b96eb05db229cf02efae2ff89 (patch) | |
tree | 276088ecddc178a54b3a0956dfa7d3ec7bd41cae /src/mongo/db/commands/apply_ops.cpp | |
parent | f23e92530e7356fa1959aac0f15cac526e46109f (diff) | |
download | mongo-05c6ae595922a89b96eb05db229cf02efae2ff89.tar.gz |
SERVER-15394 improve applyOps validation
Diffstat (limited to 'src/mongo/db/commands/apply_ops.cpp')
-rw-r--r-- | src/mongo/db/commands/apply_ops.cpp | 61 |
1 files changed, 56 insertions, 5 deletions
diff --git a/src/mongo/db/commands/apply_ops.cpp b/src/mongo/db/commands/apply_ops.cpp index 947b57b2df0..c0a1f398e56 100644 --- a/src/mongo/db/commands/apply_ops.cpp +++ b/src/mongo/db/commands/apply_ops.cpp @@ -74,11 +74,9 @@ namespace mongo { BSONObjIterator i( ops ); while ( i.more() ) { BSONElement e = i.next(); - if ( e.type() == Object ) - continue; - errmsg = "op not an object: "; - errmsg += e.fieldName(); - return false; + if (!_checkOperation(e, errmsg)) { + return false; + } } } @@ -122,6 +120,10 @@ namespace mongo { BSONElement e = i.next(); const BSONObj& temp = e.Obj(); + // Ignore 'n' operations. + const char *opType = temp["op"].valuestrsafe(); + if (*opType == 'n') continue; + string ns = temp["ns"].String(); // Run operations under a nested lock as a hack to prevent them from yielding. @@ -189,6 +191,55 @@ namespace mongo { return true; } + + private: + /** + * Returns true if 'e' contains a valid operation. + */ + bool _checkOperation(const BSONElement& e, string& errmsg) { + if (e.type() != Object) { + errmsg = str::stream() << "op not an object: " << e.fieldName(); + return false; + } + BSONObj obj = e.Obj(); + // op - operation type + BSONElement opElement = obj.getField("op"); + if (opElement.eoo()) { + errmsg = str::stream() << "op does not contain required \"op\" field: " + << e.fieldName(); + return false; + } + if (opElement.type() != mongo::String) { + errmsg = str::stream() << "\"op\" field is not a string: " << e.fieldName(); + return false; + } + // operation type -- see logOp() comments for types + const char *opType = opElement.valuestrsafe(); + if (*opType == '\0') { + errmsg = str::stream() << "\"op\" field value cannot be empty: " << e.fieldName(); + return false; + } + + // ns - namespace + // Only operations of type 'n' are allowed to have an empty namespace. + BSONElement nsElement = obj.getField("ns"); + if (nsElement.eoo()) { + errmsg = str::stream() << "op does not contain required \"ns\" field: " + << e.fieldName(); + return false; + } + if (nsElement.type() != mongo::String) { + errmsg = str::stream() << "\"ns\" field is not a string: " << e.fieldName(); + return false; + } + if (*opType != 'n' && nsElement.String().empty()) { + errmsg = str::stream() + << "\"ns\" field value cannot be empty when op type is not 'n': " + << e.fieldName(); + return false; + } + return true; + } } applyOpsCmd; } |