summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormatt dannenberg <matt.dannenberg@10gen.com>2013-07-29 16:27:09 -0400
committermatt dannenberg <matt.dannenberg@10gen.com>2013-08-09 17:48:46 -0400
commitcd81198d0280abc8144bd7fa291a15564c1c0ae4 (patch)
tree83ddb514572d6183a05bc47f5ed4c2804372e135
parentaf6828e05aaea88e181cad598cc1274e2838d25a (diff)
downloadmongo-cd81198d0280abc8144bd7fa291a15564c1c0ae4.tar.gz
SERVER-5782 $literal operator to help prevent injection attacks
-rw-r--r--jstests/aggregation/bugs/server5782.js18
-rw-r--r--jstests/aggregation/testshard1.js9
-rw-r--r--src/mongo/db/pipeline/expression.cpp3
3 files changed, 29 insertions, 1 deletions
diff --git a/jstests/aggregation/bugs/server5782.js b/jstests/aggregation/bugs/server5782.js
new file mode 100644
index 00000000000..d4ac2eeb6f1
--- /dev/null
+++ b/jstests/aggregation/bugs/server5782.js
@@ -0,0 +1,18 @@
+load('jstests/aggregation/extras/utils.js');
+
+db.server5782.drop();
+db.server5782.save({string: "foo"});
+
+// check that without $literal we end up comparing a field with itself and the result is true
+var result = db.runCommand({aggregate: "server5782",
+ pipeline:[{$project:
+ {stringis$string: {$eq:["$string", '$string']}}
+ }]});
+assert.eq(result.result[0].stringis$string, true);
+
+// check that with $literal we end up comparing a field with '$string' and the result is true
+var result = db.runCommand({aggregate: "server5782",
+ pipeline:[{$project:
+ {stringis$string: {$eq:["$string", {$literal:'$string'}]}}
+ }]});
+assert.eq(result.result[0].stringis$string, false);
diff --git a/jstests/aggregation/testshard1.js b/jstests/aggregation/testshard1.js
index 864f58db375..66dd8b261dc 100644
--- a/jstests/aggregation/testshard1.js
+++ b/jstests/aggregation/testshard1.js
@@ -24,8 +24,10 @@ db = shardedAggTest.getDB( "aggShard" );
/* make sure its cleaned up */
db.ts1.drop();
+db.literal.drop();
shardedAggTest.adminCommand( { shardcollection : "aggShard.ts1", key : { "_id" : 1 } } );
+shardedAggTest.adminCommand( { shardcollection : "aggShard.literal", key : { "_id" : 1 } } );
/*
@@ -203,5 +205,12 @@ assert.eq(db.ts1.find().sort({_id:1}).toArray(),
// Make sure we error out if $out collection is sharded
assertErrorCode(db.outCollection, [{$out: db.ts1.getName()}], 17017);
+db.literal.save({dollar:false});
+
+result = db.literal.aggregate(
+ {$project:{_id:0, cost:{$cond:['$dollar', {$literal:'$1.00'}, {$literal:'$.99'}]}}});
+
+assert.eq([{cost:'$.99'}], result.result);
+
// shut everything down
shardedAggTest.stop();
diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp
index d121b99c4e0..bb3589b66e5 100644
--- a/src/mongo/db/pipeline/expression.cpp
+++ b/src/mongo/db/pipeline/expression.cpp
@@ -273,6 +273,7 @@ namespace mongo {
{"$hour", ExpressionHour::create, OpDesc::FIXED_COUNT, 1},
{"$ifNull", ExpressionIfNull::create, OpDesc::FIXED_COUNT, 2},
// $let handled specially in parseExpression
+ // $literal handled specially in parseExpression
// $map handled specially in parseExpression
{"$lt", ExpressionCompare::createLt, OpDesc::FIXED_COUNT, 2},
{"$lte", ExpressionCompare::createLte, OpDesc::FIXED_COUNT, 2},
@@ -306,7 +307,7 @@ namespace mongo {
/* look for the specified operator */
const char* opName = exprElement.fieldName();
- if (str::equals(opName, "$const")) {
+ if (str::equals(opName, "$const") || str::equals(opName, "$literal")) {
return ExpressionConstant::createFromBsonElement(&exprElement);
}
else if (str::equals(opName, "$let")) {