diff options
author | Yuhong Zhang <yuhong.zhang@mongodb.com> | 2022-11-11 18:10:56 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-11-11 18:57:22 +0000 |
commit | 61dd3a14b837d1e9a9ac567a37245cbe7a9be6a5 (patch) | |
tree | e82bc7c36c1709ee06a1ccb77a49d658e51f79d4 | |
parent | 10f9ad49bd128b6b95804f12a641cbab684a34ca (diff) | |
download | mongo-61dd3a14b837d1e9a9ac567a37245cbe7a9be6a5.tar.gz |
SERVER-69788 Use the BSONElementValue helper in BSON validation
-rw-r--r-- | src/mongo/bson/bson_validate.cpp | 85 |
1 files changed, 45 insertions, 40 deletions
diff --git a/src/mongo/bson/bson_validate.cpp b/src/mongo/bson/bson_validate.cpp index d47f32ab2c4..cb58767049e 100644 --- a/src/mongo/bson/bson_validate.cpp +++ b/src/mongo/bson/bson_validate.cpp @@ -35,6 +35,7 @@ #include "mongo/base/data_view.h" #include "mongo/bson/bson_depth.h" #include "mongo/bson/bsonelement.h" +#include "mongo/bson/bsonelementvalue.h" #include "mongo/bson/util/bsoncolumn.h" #include "mongo/crypto/encryption_fields_util.h" #include "mongo/crypto/fle_field_schema_gen.h" @@ -102,8 +103,8 @@ public: void checkNonConformantElem(const char* ptr, uint32_t offsetToValue, uint8_t type) { // Checks the field name before the element, if inside array. checkArrIndex(ptr); - // Increments the pointer to the actual element. - ptr += offsetToValue; + // Increments the pointer to the actual element value. + BSONElementValue bsonElemVal(ptr + offsetToValue); switch (type) { case BSONType::Undefined: case BSONType::DBRef: @@ -118,14 +119,12 @@ public: addIndexLevel(false /* isArr */); break; case BSONType::RegEx: { - // Skips regular expression cstring. - const char* options = ptr + strlen(ptr) + 1; - _checkRegexOptions(options); + _checkRegexOptions(bsonElemVal); break; } case BSONType::BinData: { - uint8_t subtype = - ConstDataView(ptr + sizeof(uint32_t)).read<LittleEndian<uint8_t>>(); + auto binData = bsonElemVal.BinData(); + auto subtype = binData.type; switch (subtype) { case BinDataType::ByteArrayDeprecated: case BinDataType::bdtUUID: @@ -134,28 +133,28 @@ public: fmt::format("Use of deprecated BSON binary data subtype {}", subtype)); break; case BinDataType::newUUID: { - constexpr uint32_t UUIDLength = 16; - uint32_t l = ConstDataView(ptr).read<LittleEndian<uint32_t>>(); - uassert( - ErrorCodes::NonConformantBSON, - fmt::format("BSON UUID length should be {} bytes. Found {} instead.", - UUIDLength, - l), - l == UUIDLength); + constexpr int32_t UUIDLength = 16; + auto l = binData.length; + uassert(ErrorCodes::NonConformantBSON, + fmt::format( + "BSON UUID length should be 16 bytes. Found {} instead.", l), + l == UUIDLength); break; } case BinDataType::MD5Type: { - constexpr uint32_t md5Length = 16; - auto md5Size = ConstDataView(ptr).read<LittleEndian<uint32_t>>(); + constexpr int32_t md5Length = 16; + auto l = binData.length; uassert(NonConformantBSON, - fmt::format("MD5 must be 16 bytes, got {} instead.", md5Size), - md5Size == md5Length); + fmt::format("MD5 must be 16 bytes, got {} instead.", l), + l == md5Length); break; } case BinDataType::Encrypt: { - _checkEncryptedBSONValue(ptr); + _checkEncryptedBSONValue(binData); break; } + default: + break; } break; } @@ -202,9 +201,10 @@ private: ++indexCount.back().counter; } - void _checkRegexOptions(const char* options) { + void _checkRegexOptions(const BSONElementValue& regex) { // Checks that the options are in ascending alphabetical order and that they're all valid. std::string validRegexOptions("ilmsux"); + auto options = regex.RegexFlags(); for (const auto& option : std::string(options)) { uassert( NonConformantBSON, @@ -219,20 +219,20 @@ private: } } - void _checkEncryptedBSONValue(const char* ptr) { + void _checkEncryptedBSONValue(const BSONBinData& binData) { constexpr uint32_t UUIDLength = 16; - constexpr uint32_t minLength = sizeof(uint8_t) + UUIDLength + sizeof(uint8_t); + constexpr int32_t minLength = sizeof(uint8_t) + UUIDLength + sizeof(uint8_t); - auto len = ConstDataView(ptr).read<LittleEndian<uint32_t>>(); + auto len = binData.length; // Make sure we can read the subtype byte of the Encrypted BSON Value. uassert(ErrorCodes::NonConformantBSON, fmt::format("Invalid Encrypted BSON Value length {}", len), len); // Skip the size bytes and BinData subtype byte to the actual encrypted data. - ptr += sizeof(uint32_t) + sizeof(uint8_t); + auto data = static_cast<const char*>(binData.data); auto encryptedBinDataType = static_cast<EncryptedBinDataType>( - (uint8_t)ConstDataView(ptr).read<LittleEndian<uint8_t>>()); + (uint8_t)ConstDataView(data).read<LittleEndian<uint8_t>>()); // Only subtype 1, 2, 6, 7, and 9 can exist in MongoDB collections. switch (encryptedBinDataType) { case EncryptedBinDataType::kDeterministic: @@ -249,7 +249,7 @@ private: fmt::format("Invalid Encrypted BSON Value length {}", len), len >= minLength); auto originalBsonType = - static_cast<BSONType>((int8_t)ConstDataView(ptr + sizeof(uint8_t) + UUIDLength) + static_cast<BSONType>((int8_t)ConstDataView(data + sizeof(uint8_t) + UUIDLength) .read<LittleEndian<uint8_t>>()); uassert(ErrorCodes::NonConformantBSON, fmt::format( @@ -275,20 +275,21 @@ protected: class FullValidator : private ExtendedValidator { public: void checkNonConformantElem(const char* ptr, uint32_t offsetToValue, uint8_t type) { - registerFieldName(ptr + 1); + registerFieldName(ptr + 1 /* fieldName */, offsetToValue - 1 /* length */); ExtendedValidator::checkNonConformantElem(ptr, offsetToValue, type); + // Increments the pointer to the actual element value. + BSONElementValue bsonElemVal(ptr + offsetToValue); switch (type) { case BSONType::Array: { - objFrames.push_back({std::vector<std::string>(), false}); + objFrames.push_back({std::vector<StringData>(), false}); break; } case BSONType::Object: { - objFrames.push_back({std::vector<std::string>(), true}); + objFrames.push_back({std::vector<StringData>(), true}); break; }; case BSONType::BinData: { - uint8_t subtype = ConstDataView(ptr + offsetToValue + sizeof(uint32_t)) - .read<LittleEndian<uint8_t>>(); + auto subtype = bsonElemVal.BinData().type; switch (subtype) { case BinDataType::Column: { // Check for exceptions when decompressing. @@ -299,13 +300,16 @@ public: uasserted(NonConformantBSON, "Exception ocurred while decompressing a BSON column."); } + break; } + default: + break; } break; } case BSONType::String: { // Increment pointer to actual value and then four more to skip size. - checkUTF8Char(ptr + offsetToValue + 4); + checkUTF8Char(bsonElemVal.String()); } } } @@ -334,21 +338,22 @@ public: private: // A given frame is an object if and only if frame.second == true. - std::vector<std::pair<std::vector<std::string>, bool>> objFrames = { - {std::vector<std::string>(), true}}; + std::vector<std::pair<std::vector<StringData>, bool>> objFrames = { + {std::vector<StringData>(), true}}; - void registerFieldName(const char* ptr) { + void registerFieldName(const char* ptr, uint32_t length) { // Check the field name is UTF-8 encoded. - checkUTF8Char(ptr); + StringData fieldName(ptr, length); + checkUTF8Char(fieldName); if (objFrames.back().second) { - objFrames.back().first.emplace_back(ptr); + objFrames.back().first.emplace_back(fieldName); }; } - void checkUTF8Char(const char* ptr) { + void checkUTF8Char(StringData str) { uassert(NonConformantBSON, "Found string that doesn't follow UTF-8 encoding.", - str::validUTF8(ptr)); + str::validUTF8(str)); } }; |