mirror of
https://github.com/nlohmann/json.git
synced 2026-10-26 15:58:55 +00:00
Check the declared BSON document size before reading its content
The BSON reader compared a document's declared size with the number of bytes read only when it reached the terminator. The declared size never bounded the reads, so a SAX handler saw the keys and values of a document whose size was too small before parse error 112 was reported. The container frame now stores the position where the document ends according to its declared size. open_bson_document rejects a size below 5 (size prefix plus terminator) and an embedded document that does not end before the terminator of its enclosing document; the element loop rejects an element whose type byte leaves no room for the name terminator and the document terminator. The terminator check stays and still catches a declared size that is too large. No input that was accepted before is rejected now; documents with a wrong size are reported earlier, with fewer SAX events, a different byte position and, in three cases, a different message. The error id (parse_error.112) is unchanged and strict=false still does not skip the check. The tests that asserted the old messages and positions are updated, with the outer sizes of two inputs corrected so that they still exercise the embedded document. New tests cover the SAX events, a size below 5, and an embedded document that fits exactly. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
2 files changed
+201
-8
No files matched your search
@@ -235,6 +235,9 @@ class binary_reader
|
||||
/// UBJSON/BJData: the type marker of an optimized container, so that
|
||||
/// its elements are read without one of their own; 0 otherwise
|
||||
char_int_type type_marker;
|
||||
/// BSON: the position right after this document, according to the
|
||||
/// size it declares
|
||||
std::size_t end_position = 0;
|
||||
/// BSON: the size this document declares, in bytes
|
||||
std::int32_t declared_size = 0;
|
||||
/// whether to close this container with end_object() or end_array()
|
||||
@@ -371,6 +374,23 @@ class binary_reader
|
||||
return false;
|
||||
}
|
||||
|
||||
// the smallest document is the size prefix and the terminator
|
||||
if (JSON_HEDLEY_UNLIKELY(document_size < 5))
|
||||
{
|
||||
return bson_document_size_error("document size ", document_size, " is less than 5");
|
||||
}
|
||||
|
||||
// the declared size bounds where the document ends: an embedded
|
||||
// document must end before the terminator of the document that contains it
|
||||
const std::size_t unsigned_size = static_cast<std::size_t>(document_size);
|
||||
const std::size_t document_end = unsigned_size > (std::numeric_limits<std::size_t>::max)() - document_start
|
||||
? (std::numeric_limits<std::size_t>::max)()
|
||||
: document_start + unsigned_size;
|
||||
if (JSON_HEDLEY_UNLIKELY(!container_stack.empty() && document_end >= container_stack.back().end_position))
|
||||
{
|
||||
return bson_document_size_error("document size ", document_size, " exceeds the size of the enclosing document");
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!enter_container(is_object, detail::unknown_size())))
|
||||
{
|
||||
return false;
|
||||
@@ -378,6 +398,7 @@ class binary_reader
|
||||
|
||||
container_frame& frame = container_stack.back();
|
||||
frame.start_position = document_start;
|
||||
frame.end_position = document_end;
|
||||
frame.declared_size = document_size;
|
||||
return true;
|
||||
}
|
||||
@@ -436,6 +457,13 @@ class binary_reader
|
||||
return false;
|
||||
}
|
||||
|
||||
// an element needs at least its name's terminator, and the
|
||||
// document its own terminator, within the declared size
|
||||
if (JSON_HEDLEY_UNLIKELY(chars_read + 2 > container_stack.back().end_position))
|
||||
{
|
||||
return bson_document_size_error("document size ", container_stack.back().declared_size, " is too small for its content");
|
||||
}
|
||||
|
||||
const std::size_t element_type_parse_position = chars_read;
|
||||
key.clear();
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key)))
|
||||
@@ -4436,6 +4464,12 @@ class binary_reader
|
||||
return last_byte_error(exception_id::unexpected_byte, concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(bytes_read), ")"), "document");
|
||||
}
|
||||
|
||||
JSON_HEDLEY_NEVER_INLINE
|
||||
bool bson_document_size_error(const char* prefix, const std::int32_t document_size, const char* suffix) const
|
||||
{
|
||||
return last_byte_error(exception_id::unexpected_byte, concat(prefix, std::to_string(document_size), suffix), "document");
|
||||
}
|
||||
|
||||
JSON_HEDLEY_NEVER_INLINE
|
||||
bool bson_unsupported_type_error(const std::size_t position, const char_int_type element_type) const
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user