diff options
author | Ian Boros <ian.boros@mongodb.com> | 2021-02-03 11:28:37 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-02-04 08:13:22 +0000 |
commit | cd583b6c4d8aa2364f255992708b9bb54e110cf4 (patch) | |
tree | 7257b9c2bdd05cdede559ea1afc3f24cbbcc457c | |
parent | da77452821c355346d873a6b31160c101adc60de (diff) | |
download | mongo-cd583b6c4d8aa2364f255992708b9bb54e110cf4.tar.gz |
SERVER-53929 Add stricter parser checks around positional projection
-rw-r--r-- | jstests/core/positional_projection.js | 8 | ||||
-rw-r--r-- | src/mongo/db/query/projection_parser.cpp | 12 | ||||
-rw-r--r-- | src/mongo/db/query/projection_test.cpp | 37 |
3 files changed, 36 insertions, 21 deletions
diff --git a/jstests/core/positional_projection.js b/jstests/core/positional_projection.js index 256dd774e1d..04c1c28d16d 100644 --- a/jstests/core/positional_projection.js +++ b/jstests/core/positional_projection.js @@ -2,6 +2,7 @@ // @tags: [ // requires_getmore, // sbe_incompatible, +// requires_fcv_49 // ] (function() { "use strict"; @@ -103,7 +104,7 @@ assert(coll.drop()); // Tests with invalid positional projection operator. assert.commandWorked(coll.insert([{x: [{a: 1, b: 2}, {a: 2, c: 3}, {a: 1, d: 5}], y: [{aa: 1}]}])); -const err = assert.throws(() => coll.find({x: 1}, {'x.$': {'$slice': 1}}).toArray()); +let err = assert.throws(() => coll.find({x: 1}, {'x.$': {'$slice': 1}}).toArray()); assert.commandFailedWithCode(err, 31271); assert.throws(function() { @@ -113,4 +114,9 @@ assert.throws(function() { assert.throws(function() { coll.find({'x.a': 1, 'y.aa': 1}, {'x.$': 1, 'y.$': 1}).toArray(); }, []); + +err = assert.throws(function() { + coll.find({}, {".$": 1}).toArray(); +}, []); +assert.commandFailedWithCode(err, 5392900); }()); diff --git a/src/mongo/db/query/projection_parser.cpp b/src/mongo/db/query/projection_parser.cpp index bc0f6944dd4..cae66cf48bf 100644 --- a/src/mongo/db/query/projection_parser.cpp +++ b/src/mongo/db/query/projection_parser.cpp @@ -395,6 +395,7 @@ void parseInclusion(ParseContext* ctx, } } else { verifyComputedFieldsAllowed(ctx->policies); + StringData elemFieldName = elem.fieldNameStringData(); uassert(31276, "Cannot specify more than one positional projection per query.", @@ -403,10 +404,15 @@ void parseInclusion(ParseContext* ctx, uassert(31256, "Cannot specify positional operator and $elemMatch.", !ctx->hasElemMatch); uassert(51050, "Projections with a positional operator require a matcher", ctx->query); + // Special case: ".$" is not considered a valid projection. + uassert(5392900, + str::stream() << "Projection on field " << elemFieldName << " is invalid", + elemFieldName != ".$"); + // Get everything up to the first positional operator. - // Should at least be ".$" - StringData elemFieldName = elem.fieldNameStringData(); - invariant(elemFieldName.size() > 2); + tassert(5392901, + "Expected element field name size to be greater than 2", + elemFieldName.size() > 2); StringData pathWithoutPositionalOperator = elemFieldName.substr(0, elemFieldName.size() - 2); diff --git a/src/mongo/db/query/projection_test.cpp b/src/mongo/db/query/projection_test.cpp index 656bef301e4..398cd3a7da2 100644 --- a/src/mongo/db/query/projection_test.cpp +++ b/src/mongo/db/query/projection_test.cpp @@ -78,7 +78,7 @@ projection_ast::Projection createFindProjection(const char* queryStr, const char return createProjection(query, projObj, ProjectionPolicies::findProjectionPolicies()); } -void assertInvalidProjection(const char* queryStr, const char* projStr) { +void assertInvalidFindProjection(const char* queryStr, const char* projStr, size_t errCode) { BSONObj query = fromjson(queryStr); BSONObj projObj = fromjson(projStr); QueryTestServiceContext serviceCtx; @@ -88,9 +88,13 @@ void assertInvalidProjection(const char* queryStr, const char* projStr) { StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse(query, expCtx); ASSERT_OK(statusWithMatcher.getStatus()); std::unique_ptr<MatchExpression> queryMatchExpr = std::move(statusWithMatcher.getValue()); - ASSERT_THROWS( - projection_ast::parse(expCtx, projObj, queryMatchExpr.get(), query, ProjectionPolicies{}), - DBException); + ASSERT_THROWS_CODE(projection_ast::parse(expCtx, + projObj, + queryMatchExpr.get(), + query, + ProjectionPolicies::findProjectionPolicies()), + DBException, + errCode); } TEST(QueryProjectionTest, MakeEmptyProjection) { @@ -153,32 +157,31 @@ TEST(QueryProjectionTest, MakeSingleFieldFalseIdBoolean) { // TEST(QueryProjectionTest, InvalidPositionalOperatorProjections) { - assertInvalidProjection("{}", "{'a.$': 1}"); - assertInvalidProjection("{a: 1}", "{'b.$': 1}"); - assertInvalidProjection("{a: 1}", "{'a.$': 0}"); - assertInvalidProjection("{a: 1}", "{'a.$.d.$': 1}"); - assertInvalidProjection("{a: 1}", "{'a.$.$': 1}"); - assertInvalidProjection("{a: 1, b: 1, c: 1}", "{'abc.$': 1}"); - assertInvalidProjection("{$or: [{a: 1}, {$or: [{b: 1}, {c: 1}]}]}", "{'d.$': 1}"); - assertInvalidProjection("{a: [1, 2, 3]}", "{'.$': 1}"); + assertInvalidFindProjection("{a: 1}", "{'a.$': 0}", 31395); + assertInvalidFindProjection("{a: 1}", "{'a.$.d.$': 1}", 31394); + assertInvalidFindProjection("{a: 1}", "{'a.$.$': 1}", 31394); + assertInvalidFindProjection("{a: [1, 2, 3]}", "{'.$': 1}", 5392900); } TEST(QueryProjectionTest, InvalidElemMatchTextProjection) { - assertInvalidProjection("{}", "{a: {$elemMatch: {$text: {$search: 'str'}}}}"); + assertInvalidFindProjection( + "{}", "{a: {$elemMatch: {$text: {$search: 'str'}}}}", ErrorCodes::BadValue); } TEST(QueryProjectionTest, InvalidElemMatchWhereProjection) { - assertInvalidProjection("{}", "{a: {$elemMatch: {$where: 'this.a == this.b'}}}"); + assertInvalidFindProjection( + "{}", "{a: {$elemMatch: {$where: 'this.a == this.b'}}}", ErrorCodes::BadValue); } TEST(QueryProjectionTest, InvalidElemMatchGeoNearProjection) { - assertInvalidProjection( + assertInvalidFindProjection( "{}", - "{a: {$elemMatch: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}}"); + "{a: {$elemMatch: {$nearSphere: {$geometry: {type: 'Point', coordinates: [0, 0]}}}}}", + ErrorCodes::BadValue); } TEST(QueryProjectionTest, InvalidElemMatchExprProjection) { - assertInvalidProjection("{}", "{a: {$elemMatch: {$expr: 5}}}"); + assertInvalidFindProjection("{}", "{a: {$elemMatch: {$expr: 5}}}", ErrorCodes::BadValue); } TEST(QueryProjectionTest, ValidPositionalOperatorProjections) { |