diff options
author | Alya Berciu <alya.berciu@mongodb.com> | 2023-04-12 13:13:04 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-04-12 13:57:33 +0000 |
commit | feca2cd33e6d317374363f008a214aebabce6a52 (patch) | |
tree | 582a5090a7d4df651a494abb679c8e6b7fe31606 | |
parent | 46832492a977b636552649f00cfdb9e2c242cebf (diff) | |
download | mongo-feca2cd33e6d317374363f008a214aebabce6a52.tar.gz |
SERVER-75517 Add additional dollar-prefix validation in _id
-rw-r--r-- | etc/backports_required_for_multiversion_tests.yml | 4 | ||||
-rw-r--r-- | jstests/core/field_name_validation.js | 10 | ||||
-rw-r--r-- | src/mongo/db/update/storage_validation.cpp | 33 |
3 files changed, 36 insertions, 11 deletions
diff --git a/etc/backports_required_for_multiversion_tests.yml b/etc/backports_required_for_multiversion_tests.yml index 1f45533046e..56e36f3cc87 100644 --- a/etc/backports_required_for_multiversion_tests.yml +++ b/etc/backports_required_for_multiversion_tests.yml @@ -326,6 +326,8 @@ last-continuous: ticket: SERVER-74460 - test_file: jstests/sharding/query/group_plan_cache_sharded.js ticket: SERVER-74245 + - test_file: jstests/core/field_name_validation.js + ticket: SERVER-75517 suites: null last-lts: all: @@ -715,4 +717,6 @@ last-lts: ticket: SERVER-73938 - test_file: jstests/sharding/shard_keys_with_dollar_sign.js ticket: SERVER-74124 + - test_file: jstests/core/field_name_validation.js + ticket: SERVER-75517 suites: null diff --git a/jstests/core/field_name_validation.js b/jstests/core/field_name_validation.js index 7dd249f98b2..42d0d5cf21d 100644 --- a/jstests/core/field_name_validation.js +++ b/jstests/core/field_name_validation.js @@ -66,6 +66,9 @@ assert.commandWorked(coll.insert({_id: 2, $valid: 1, $db: 1})); assert.commandWorked(coll.insert({_id: 3, $valid: 1, $ref: 1})); assert.commandWorked(coll.insert({_id: 4, $valid: 1, $alsoValid: 1})); +// Valid, because _id.$gt is a field name, and not equivalent to {_id: {$gt: 4}} +assert.commandWorked(coll.insert({"_id.$gt": 4})); + // // Update command field name validation. // @@ -93,9 +96,16 @@ assert.writeErrorWithCode(coll.update({"a.b": 1}, {_id: {$invalid: 1}}, {upsert: ErrorCodes.DollarPrefixedFieldName); assert.writeErrorWithCode(coll.update({"a.b": 1}, {$set: {_id: {$invalid: 1}}}, {upsert: true}), ErrorCodes.DollarPrefixedFieldName); +assert.writeErrorWithCode(coll.update({"a.b": 1}, {$set: {"_id.$gt": 1}}, {upsert: true}), + ErrorCodes.DollarPrefixedFieldName); assert.writeErrorWithCode( coll.update({"a.b": 1}, {$setOnInsert: {_id: {$invalid: 1}}}, {upsert: true}), ErrorCodes.DollarPrefixedFieldName); +assert.writeErrorWithCode( + coll.update({"a.b": 1}, {$setOnInsert: {"_id.$invalid": 1}}, {upsert: true}), + ErrorCodes.DollarPrefixedFieldName); +assert.writeErrorWithCode(coll.update({"_id.$gt": 1}, {$set: {a: 1}}, {upsert: true}), + ErrorCodes.DollarPrefixedFieldName); // Replacement-style updates can contain nested $-prefixed fields. assert.commandWorked(coll.update({"a.b": 1}, {a: {$c: 1}})); diff --git a/src/mongo/db/update/storage_validation.cpp b/src/mongo/db/update/storage_validation.cpp index 0feb5877ef5..c02d42a0b27 100644 --- a/src/mongo/db/update/storage_validation.cpp +++ b/src/mongo/db/update/storage_validation.cpp @@ -152,19 +152,30 @@ void scanDocument(const mutablebson::Document& doc, auto currElem = doc.root().leftChild(); while (currElem.ok()) { if (currElem.getFieldName() == idFieldName && shouldValidate) { - uassertStatusOK(storageValidIdField(currElem.getValue())); + if (currElem.getType() == BSONType::Object) { + // We need to recursively validate the _id field while ensuring we disallow + // top-level $-prefix fields in the _id object. + scanDocument(currElem, + true /* deep */, + 0 /* recursionLevel - forces _id fields to be treated as top-level. */, + false /* Top-level _id fields cannot be $-prefixed. */, + shouldValidate, + containsDotsAndDollarsField); + } else { + uassertStatusOK(storageValidIdField(currElem.getValue())); + } + } else { + // Validate this child element. + const auto deep = true; + const uint32_t recursionLevel = 1; + scanDocument(currElem, + deep, + recursionLevel, + allowTopLevelDollarPrefixes, + shouldValidate, + containsDotsAndDollarsField); } - // Validate this child element. - const auto deep = true; - const uint32_t recursionLevel = 1; - scanDocument(currElem, - deep, - recursionLevel, - allowTopLevelDollarPrefixes, - shouldValidate, - containsDotsAndDollarsField); - currElem = currElem.rightSibling(); } } |