Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion bson/_cbsonmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2432,6 +2432,9 @@ static PyObject* get_value(PyObject* self, PyObject* name, const char* buffer,
}
case 8:
{
if (max < 1) {
goto invalid;
}
char boolean_raw = buffer[(*position)++];
if (0 == boolean_raw) {
value = Py_False;
Expand Down Expand Up @@ -2485,7 +2488,9 @@ static PyObject* get_value(PyObject* self, PyObject* name, const char* buffer,
}
*position += (unsigned)pattern_length + 1;
start += pattern_length + 1;
const char* flags_nul = memchr(start, 0, max - pattern_length);
/* PYTHON-6111: account for the pattern NUL consumed above so
* the flags terminator cannot overlap the document terminator. */
const char* flags_nul = memchr(start, 0, max - pattern_length - 1);
if (!flags_nul) {
Py_DECREF(pattern);
goto invalid;
Expand Down
4 changes: 4 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,13 @@ Bug fixes
any field contains the reserved ``|`` delimiter (`PYTHON-6040`_).
- Fixed a bug in SRV polling where invalid hosts where topology would not be
updated if one returned host was invalid.
- Fixed a bug where the C extension's BSON decoder accepted documents whose
element data overlaps the document terminator instead of raising
``InvalidBSON`` (`PYTHON-6111`_).

.. _PYTHON-6074: https://jira.mongodb.org/browse/PYTHON-6074
.. _PYTHON-6040: https://jira.mongodb.org/browse/PYTHON-6040
.. _PYTHON-6111: https://jira.mongodb.org/browse/PYTHON-6111

Changes in Version 4.18.2 (2026/09/24)
--------------------------------------
Expand Down
34 changes: 34 additions & 0 deletions test/test_bson.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,40 @@ def test_regex_empty_flags(self):
self.assertEqual(decode(mm), expected)
self.assertEqual(decode_all(mm), [expected])

def test_element_overlaps_document_terminator(self):
# PYTHON-6111: an element whose value would consume the document
# terminator byte must be rejected, matching the pure-Python decoder.
bad_bsons = [
# Boolean value byte is the document terminator.
b"\x08\x00\x00\x00\x08a\x00\x00",
# Regex pattern terminator is the document terminator.
b"\x08\x00\x00\x00\x0ba\x00\x00",
# Regex flags terminator is the document terminator.
b"\x0a\x00\x00\x00\x0ba\x00b\x00\x00",
]
for data in bad_bsons:
msg = f"bad_bson={data!r}"
self.assertFalse(is_valid(data), msg=msg)
with self.assertRaises(InvalidBSON, msg=msg):
decode(data)
with self.assertRaises(InvalidBSON, msg=msg):
decode(bytearray(data))
with self.assertRaises(InvalidBSON, msg=msg):
decode(memoryview(data))
with self.assertRaises(InvalidBSON, msg=msg):
decode(array.array("B", data))
with self.assertRaises(InvalidBSON, msg=msg):
list(decode_iter(data))
with self.assertRaises(InvalidBSON, msg=msg):
decode_all(data)
with mmap.mmap(-1, len(data)) as mm:
mm.write(data)
mm.seek(0)
with self.assertRaises(InvalidBSON, msg=msg):
decode(mm)
with self.assertRaises(InvalidBSON, msg=msg):
decode_all(mm)

def test_data_timestamp(self):
self.assertEqual(
{"test": Timestamp(4, 20)},
Expand Down
Loading