mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-11-14 16:07:25 +00:00
python3-pymongo: Fix CVE-2026-106435
This patch applies the upstream fix as referenced in [3], using the commit shown in [1] and regression commit from [2]. Follow up the PYTHON-6110 CVE fix: its regex flags scan leaves a one-byte boundary error after consuming the pattern terminator. Apply PYTHON-6111's correction and terminator-overlap regression test. [1] https://github.com/mongodb/mongo-python-driver/commit/bb8d4e195275e75bd94ebeffb53cc747d357fcf4 [2] https://github.com/mongodb/mongo-python-driver/commit/b5a36ccbdb97298fbf9b5b5767affe92c534461f [3] https://jira.mongodb.org/browse/PYTHON-6110 [4] https://jira.mongodb.org/browse/PYTHON-6111 Signed-off-by: Yogita Urade <yurade@cisco.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
1 parent
a5890d9b37
commit
2332d83cbd
3 files changed
+218
-1
No files matched your search
@@ -0,0 +1,92 @@
|
||||
From b5a36ccbdb97298fbf9b5b5767affe92c534461f Mon Sep 17 00:00:00 2001
|
||||
From: Steven Silvester <steve.silvester@mongodb.com>
|
||||
Date: Tue, 13 Oct 2026 09:30:43 -0500
|
||||
Subject: [PATCH] PYTHON-6111 C extension accepts BSON documents where element
|
||||
data overlaps the document terminator (#3113)
|
||||
|
||||
CVE: CVE-2026-106435
|
||||
Upstream-Status: Backport [https://github.com/mongodb/mongo-python-driver/commit/b5a36ccbdb97298fbf9b5b5767affe92c534461f]
|
||||
|
||||
Backport Changes:
|
||||
- Omitted doc/changelog.rst because the release note is documentation-only.
|
||||
|
||||
(cherry picked from commit b5a36ccbdb97298fbf9b5b5767affe92c534461f)
|
||||
Signed-off-by: Yogita Urade <yurade@cisco.com>
|
||||
---
|
||||
bson/_cbsonmodule.c | 7 ++++++-
|
||||
test/test_bson.py | 34 ++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 40 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/bson/_cbsonmodule.c b/bson/_cbsonmodule.c
|
||||
index 3f141040..44cc9375 100644
|
||||
--- a/bson/_cbsonmodule.c
|
||||
+++ b/bson/_cbsonmodule.c
|
||||
@@ -2221,6 +2221,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;
|
||||
@@ -2274,7 +2277,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;
|
||||
diff --git a/test/test_bson.py b/test/test_bson.py
|
||||
index bc367bc2..47511567 100644
|
||||
--- a/test/test_bson.py
|
||||
+++ b/test/test_bson.py
|
||||
@@ -446,6 +446,40 @@ class TestBSON(unittest.TestCase):
|
||||
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.
|
||||
+ ("boolean value", b"\x08\x00\x00\x00\x08a\x00\x00"),
|
||||
+ # Regex pattern terminator is the document terminator.
|
||||
+ ("regex pattern", b"\x08\x00\x00\x00\x0ba\x00\x00"),
|
||||
+ # Regex flags terminator is the document terminator.
|
||||
+ ("regex flags", b"\x0a\x00\x00\x00\x0ba\x00b\x00\x00"),
|
||||
+ ]
|
||||
+ for description, data in bad_bsons:
|
||||
+ with self.subTest(description, bad_bson=data):
|
||||
+ self.assertFalse(is_valid(data))
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ decode(data)
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ decode(bytearray(data))
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ decode(memoryview(data))
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ decode(array.array("B", data))
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ list(decode_iter(data))
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ decode_all(data)
|
||||
+ with mmap.mmap(-1, len(data)) as mm:
|
||||
+ mm.write(data)
|
||||
+ mm.seek(0)
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ decode(mm)
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ decode_all(mm)
|
||||
+
|
||||
def test_data_timestamp(self):
|
||||
self.assertEqual(
|
||||
{"test": Timestamp(4, 20)},
|
||||
--
|
||||
2.35.6
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
From bb8d4e195275e75bd94ebeffb53cc747d357fcf4 Mon Sep 17 00:00:00 2001
|
||||
From: Jeffrey 'Alex' Clark <aclark@aclark.net>
|
||||
Date: Thu, 8 Oct 2026 14:45:52 -0400
|
||||
Subject: [PATCH] PYTHON-6110 Bound Regex element scans to the remaining
|
||||
document bytes (#3109)
|
||||
|
||||
Co-authored-by: Steven Silvester <steve.silvester@mongodb.com>
|
||||
|
||||
CVE: CVE-2026-106435
|
||||
Upstream-Status: Backport [https://github.com/mongodb/mongo-python-driver/commit/bb8d4e195275e75bd94ebeffb53cc747d357fcf4]
|
||||
|
||||
(cherry picked from commit bb8d4e195275e75bd94ebeffb53cc747d357fcf4)
|
||||
Signed-off-by: Yogita Urade <yurade@cisco.com>
|
||||
---
|
||||
bson/_cbsonmodule.c | 23 ++++++++++++++++-------
|
||||
test/test_bson.py | 45 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 61 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/bson/_cbsonmodule.c b/bson/_cbsonmodule.c
|
||||
index 7d184641..3f141040 100644
|
||||
--- a/bson/_cbsonmodule.c
|
||||
+++ b/bson/_cbsonmodule.c
|
||||
@@ -2255,24 +2255,33 @@ static PyObject* get_value(PyObject* self, PyObject* name, const char* buffer,
|
||||
PyObject* pattern;
|
||||
int flags;
|
||||
size_t flags_length, i;
|
||||
- size_t pattern_length = strlen(buffer + *position);
|
||||
- if (pattern_length > BSON_MAX_SIZE || max < pattern_length) {
|
||||
+ /* PYTHON-6110: Search for each NUL within the bytes remaining
|
||||
+ * in the document rather than scanning the buffer. */
|
||||
+ const char* start = buffer + *position;
|
||||
+ const char* pattern_nul = memchr(start, 0, max);
|
||||
+ if (!pattern_nul) {
|
||||
+ goto invalid;
|
||||
+ }
|
||||
+ size_t pattern_length = (size_t)(pattern_nul - start);
|
||||
+ if (pattern_length > BSON_MAX_SIZE) {
|
||||
goto invalid;
|
||||
}
|
||||
pattern = PyUnicode_DecodeUTF8(
|
||||
- buffer + *position, pattern_length,
|
||||
+ start, pattern_length,
|
||||
options->unicode_decode_error_handler);
|
||||
if (!pattern) {
|
||||
goto invalid;
|
||||
}
|
||||
*position += (unsigned)pattern_length + 1;
|
||||
- flags_length = strlen(buffer + *position);
|
||||
- if (flags_length > BSON_MAX_SIZE ||
|
||||
- (BSON_MAX_SIZE - pattern_length) < flags_length) {
|
||||
+ start += pattern_length + 1;
|
||||
+ const char* flags_nul = memchr(start, 0, max - pattern_length);
|
||||
+ if (!flags_nul) {
|
||||
Py_DECREF(pattern);
|
||||
goto invalid;
|
||||
}
|
||||
- if (max < pattern_length + flags_length) {
|
||||
+ flags_length = (size_t)(flags_nul - start);
|
||||
+ if (flags_length > BSON_MAX_SIZE ||
|
||||
+ (BSON_MAX_SIZE - pattern_length) < flags_length) {
|
||||
Py_DECREF(pattern);
|
||||
goto invalid;
|
||||
}
|
||||
diff --git a/test/test_bson.py b/test/test_bson.py
|
||||
index ffc02965..bc367bc2 100644
|
||||
--- a/test/test_bson.py
|
||||
+++ b/test/test_bson.py
|
||||
@@ -401,6 +401,51 @@ class TestBSON(unittest.TestCase):
|
||||
# Assert that the InvalidBSON error message is not empty.
|
||||
self.assertTrue(str(ctx.exception))
|
||||
|
||||
+ def test_malformed_regex(self):
|
||||
+ # PYTHON-6110: decoding a malformed Regex element must raise
|
||||
+ # InvalidBSON on every accepted buffer type.
|
||||
+ malformed = []
|
||||
+ for pattern in ("", "x", "xx"):
|
||||
+ doc = bytearray(encode({"a": Regex(pattern, "")}))
|
||||
+ # Drop the trailing flags NUL and document EOO bytes, leaving
|
||||
+ # the flags string unterminated after the pattern's NUL.
|
||||
+ del doc[-2:]
|
||||
+ # Keep the length prefix consistent with the shorter document.
|
||||
+ doc[:4] = struct.pack("<i", len(doc))
|
||||
+ malformed.append(bytes(doc))
|
||||
+ for data in malformed:
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ decode(data)
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ decode(bytearray(data))
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ decode(memoryview(data))
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ decode(array.array("B", data))
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ list(decode_iter(data))
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ decode_all(data)
|
||||
+ with mmap.mmap(-1, len(data)) as mm:
|
||||
+ mm.write(data)
|
||||
+ mm.seek(0)
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ decode(mm)
|
||||
+ with self.assertRaises(InvalidBSON):
|
||||
+ decode_all(mm)
|
||||
+
|
||||
+ def test_regex_empty_flags(self):
|
||||
+ # PYTHON-6110: a valid regex with an empty flags string must
|
||||
+ # continue to decode.
|
||||
+ valid = encode({"a": Regex("b", "")})
|
||||
+ expected = {"a": Regex("b", 0)}
|
||||
+ self.assertEqual(decode(valid), expected)
|
||||
+ with mmap.mmap(-1, len(valid)) as mm:
|
||||
+ mm.write(valid)
|
||||
+ mm.seek(0)
|
||||
+ self.assertEqual(decode(mm), expected)
|
||||
+ self.assertEqual(decode_all(mm), [expected])
|
||||
+
|
||||
def test_data_timestamp(self):
|
||||
self.assertEqual(
|
||||
{"test": Timestamp(4, 20)},
|
||||
--
|
||||
2.35.6
|
||||
|
||||
@@ -8,7 +8,10 @@ HOMEPAGE = "https://github.com/mongodb/mongo-python-driver"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327"
|
||||
|
||||
SRC_URI += "file://CVE-2026-88029.patch"
|
||||
SRC_URI += "file://CVE-2026-88029.patch \
|
||||
file://CVE-2026-106435.patch \
|
||||
file://CVE-2026-106435-regression.patch \
|
||||
"
|
||||
|
||||
SRC_URI[sha256sum] = "8ba8405065f6e258a6f872fe62d797a28f383a12178c7153c01ed04e845c600c"
|
||||
|
||||
|
||||
Reference in new issue
Block a user