Skip to content

Commit

Permalink
SERVER-84125: Check fieldname size in BSONColumn validation (#17688)
Browse files Browse the repository at this point in the history
  • Loading branch information
binhvomongodb committed Dec 19, 2023
1 parent 417766d commit d9092c9
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 7 deletions.
17 changes: 10 additions & 7 deletions src/mongo/bson/bson_validate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,29 +436,32 @@ class ValidateBuffer {

/* Assumes the root level is a single literal element (which may contain nested objects).
* Only validates up to the termination of that first literal, more data is permitted to
remain in the buffer after that and is not validated. Throws exception on invalid data*/
* remain in the buffer after that and is not validated. Throws exception on invalid data.
* Confirm field names for literals in BSONColumn have empty field names.
*/
int validateAndMeasureElem() {
setupValidation();
uassert(InvalidBSON,
"BSON literal is not followed by fieldname",
_maxLength > 1); // must at least have a 0-terminator after control
size_t fieldNameSize = strnlen(_data + 1 /* skip type */, _maxLength - 1) + 1;
// Confirm fieldName is just a null terminator
uassert(NonConformantBSON,
"BSON literal content does not have an empty fieldname",
_maxLength > 1 && _data[1] == 0);

// Handle one element without using iterative loop, and without expecting
// multiple instances or an EOO. Only resume with the iterative loop if
// the frame stack has been incremented, meaning we have nested objects

// Save pointer to currFrame->end so we can fill it in once we know the size
const char** preEnd = &(_currFrame->end);
const char* ptr =
_validateElem(Cursor{_data + 1 + fieldNameSize, _data + _maxLength}, *_data);
_validator.checkNonConformantElem(_data, 1 + fieldNameSize, *_data);
const char* ptr = _validateElem(Cursor{_data + 2, _data + _maxLength}, *_data);
_validator.checkNonConformantElem(_data, 2, *_data);

if (_currFrame != _frames.begin()) {
// We know that type was kObject or kArray, so size is fieldname, type,
// and a stored int
int size = 1 + fieldNameSize +
ConstDataView(_data + fieldNameSize + 1).read<LittleEndian<int32_t>>();
int size = 2 + ConstDataView(_data + 2).read<LittleEndian<int32_t>>();
uassert(InvalidBSON,
"BSON literal content exceeds buffer size",
(size_t)size <= _maxLength);
Expand Down
18 changes: 18 additions & 0 deletions src/mongo/bson/bson_validate_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,24 @@ TEST(BSONValidateColumn, BSONColumnMissingEOO) {
ErrorCodes::InvalidBSON);
}

TEST(BSONValidateColumn, BSONColumnFieldnameNotEmpty) {
BSONColumnBuilder cb;
cb.append(BSON("a"
<< "deadbeef")
.getField("a"));
BSONBinData columnData = cb.finalize();
ASSERT_OK(validateBSONColumn((char*)columnData.data, columnData.length));

char buf[1024];
buf[0] = ((const char*)columnData.data)[0];
buf[1] = 'f';
buf[2] = 'o';
buf[3] = 'o';
memcpy(buf + 4, ((const char*)columnData.data) + 1, columnData.length - 1);

ASSERT_EQ(validateBSONColumn(buf, columnData.length + 3).code(), ErrorCodes::NonConformantBSON);
}

TEST(BSONValidateColumn, BSONColumnNoOverflowMissingAllEOOInColumn) {
BSONColumnBuilder cb;
cb.append(BSON("a"
Expand Down

0 comments on commit d9092c9

Please sign in to comment.