summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRichard Hausman <richard.hausman@mongodb.com>2022-08-09 14:19:38 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-08-09 16:08:36 +0000
commitdd1737cd88864b9051dd018c7a449d34b59cc347 (patch)
tree5133ac59c5d4dc0284be0143e8438b1c5b31310f /src
parentd19f16b760c4c6ae4f4729557b548a11649b670b (diff)
downloadmongo-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.cpp31
-rw-r--r--src/mongo/bson/bson_validate_test.cpp29
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()};