diff options
author | Richard Hausman <richard.hausman@mongodb.com> | 2022-08-09 14:19:38 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-08-09 16:08:36 +0000 |
commit | dd1737cd88864b9051dd018c7a449d34b59cc347 (patch) | |
tree | 5133ac59c5d4dc0284be0143e8438b1c5b31310f /src | |
parent | d19f16b760c4c6ae4f4729557b548a11649b670b (diff) | |
download | mongo-dd1737cd88864b9051dd018c7a449d34b59cc347.tar.gz |
SERVER-67881 : Check unsupported regular expression options in BSON documents in the validate command.
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/bson/bson_validate.cpp | 31 | ||||
-rw-r--r-- | src/mongo/bson/bson_validate_test.cpp | 29 |
2 files changed, 58 insertions, 2 deletions
diff --git a/src/mongo/bson/bson_validate.cpp b/src/mongo/bson/bson_validate.cpp index c53607a4bb1..613ab5e51ca 100644 --- a/src/mongo/bson/bson_validate.cpp +++ b/src/mongo/bson/bson_validate.cpp @@ -100,10 +100,11 @@ public: case BSONType::Undefined: case BSONType::DBRef: case BSONType::Symbol: - case BSONType::CodeWScope: + case BSONType::CodeWScope: { uasserted(NonConformantBSON, fmt::format("Use of deprecated BSON type {}", type)); break; - case BSONType::BinData: + } + case BSONType::BinData: { uint8_t subtype = ConstDataView(ptr + sizeof(uint32_t)).read<LittleEndian<uint8_t>>(); switch (subtype) { @@ -132,12 +133,38 @@ public: md5Size == md5Length); break; } + break; + } + case BSONType::RegEx: { + // Skips regular expression cstring. + const char* options = ptr + strlen(ptr) + 1; + _checkRegexOptions(options); // this might not work + break; + } } } void checkUTF8Char() {} void checkDuplicateFieldName() {} + +private: + void _checkRegexOptions(const char* options) { + // Checks that the options are in ascending alphabetical order and that they're all valid. + std::string validRegexOptions("ilmsux"); + for (const auto& option : std::string(options)) { + uassert( + NonConformantBSON, + fmt::format("Valid regex options are [ i, l, m, s, u, x], but found '{}' instead.", + option), + validRegexOptions.find(option) != std::string::npos); + uassert(NonConformantBSON, + fmt::format("Regex options should be in ascending alphabetical order. " + "Found {} instead.", + options), + &option == options || option > *(&option - 1)); + } + } }; class FullValidator : private ExtendedValidator { diff --git a/src/mongo/bson/bson_validate_test.cpp b/src/mongo/bson/bson_validate_test.cpp index 455c9382927..2ce25da5ab7 100644 --- a/src/mongo/bson/bson_validate_test.cpp +++ b/src/mongo/bson/bson_validate_test.cpp @@ -451,6 +451,35 @@ TEST(BSONValidateFast, MaxNestingDepth) { ASSERT_EQ(status.code(), ErrorCodes::Overflow); } +TEST(BSONValidateExtended, RegexOptions) { + // Checks that RegEx with invalid options strings (either an unknown flag or not in alphabetical + // order) throws a warning. + std::pair<Status, Status> stats{Status::OK(), Status::OK()}; + auto fullyValidate = [&](BSONObj obj) { + return std::pair{validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kExtended), + validateBSON(obj.objdata(), obj.objsize(), BSONValidateMode::kFull)}; + }; + BSONObj obj = BSON("a" << BSONRegEx("a*.conn", "ilmsux")); + stats = fullyValidate(obj); + ASSERT_OK(stats.first); + ASSERT_OK(stats.second); + + obj = BSON("a" << BSONRegEx("a*.conn", "ilmxus")); + stats = fullyValidate(obj); + ASSERT_EQ(stats.first, ErrorCodes::NonConformantBSON); + ASSERT_EQ(stats.second, ErrorCodes::NonConformantBSON); + + obj = BSON("a" << BSONRegEx("a*.conn", "ikl")); + stats = fullyValidate(obj); + ASSERT_EQ(stats.first, ErrorCodes::NonConformantBSON); + ASSERT_EQ(stats.second, ErrorCodes::NonConformantBSON); + + obj = BSON("a" << BSONRegEx("a*.conn", "ilmz")); + stats = fullyValidate(obj); + ASSERT_EQ(stats.first, ErrorCodes::NonConformantBSON); + ASSERT_EQ(stats.second, ErrorCodes::NonConformantBSON); +} + TEST(BSONValidateExtended, UUIDLength) { // Checks that an invalid UUID length (!= 16 bytes) throws a warning. std::pair<Status, Status> stats{Status::OK(), Status::OK()}; |