Version in base suite: 1.30.4-1+deb13u1 Base version: mongo-c-driver_1.30.4-1+deb13u1 Target version: mongo-c-driver_1.30.4-1+deb13u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/m/mongo-c-driver/mongo-c-driver_1.30.4-1+deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/m/mongo-c-driver/mongo-c-driver_1.30.4-1+deb13u2.dsc changelog | 18 patches/0002_CVE-2026-6231.patch | 1079 ++++++++++++++++++++++++++++++++++++++ patches/0003_CVE-2026-6231.patch | 27 patches/0004_CVE-2026-4359.patch | 36 + patches/0005_CDRIVER-6281.patch | 92 +++ patches/0006_CVE-2025-14911.patch | 56 + patches/0007_CVE-2025-14911.patch | 49 + patches/0008_CVE-2026-6691.patch | 39 + patches/series | 7 9 files changed, 1403 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp7j9ffyg2/mongo-c-driver_1.30.4-1+deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp7j9ffyg2/mongo-c-driver_1.30.4-1+deb13u2.dsc: no acceptable signature found diff -Nru mongo-c-driver-1.30.4/debian/changelog mongo-c-driver-1.30.4/debian/changelog --- mongo-c-driver-1.30.4/debian/changelog 2025-12-18 19:50:07.000000000 +0000 +++ mongo-c-driver-1.30.4/debian/changelog 2026-04-27 15:48:27.000000000 +0000 @@ -1,3 +1,21 @@ +mongo-c-driver (1.30.4-1+deb13u2) trixie; urgency=medium + + * Fix CVE-2026-6231: bson_validate may skip validation when processing + certain inputs + * Fix CVE-2026-4359: a compromised third party cloud server or + man-in-the-middle attacker could send a malformed HTTP response and cause + an application crash + * Fix: improve handling of corrupt GridFS files (upstream ticket: + https://jira.mongodb.org/browse/CDRIVER-6281) + * Fix CVE-2025-14911: user-controlled chunkSize metadata from lacks + appropriate validation allowing malformed GridFS metadata to overflow the + bounding container + * Fix CVE-2026-6691: Cyrus SASL integration performs unsafe string copying + during username canonicalization, enabling a heap buffer overflow before + any authentication or network traffic + + -- Roberto C. Sanchez Mon, 27 Apr 2026 11:48:27 -0400 + mongo-c-driver (1.30.4-1+deb13u1) trixie; urgency=medium * Fix CVE-2025-12119: mongoc_bulk_operation_t may read invalid memory if diff -Nru mongo-c-driver-1.30.4/debian/patches/0002_CVE-2026-6231.patch mongo-c-driver-1.30.4/debian/patches/0002_CVE-2026-6231.patch --- mongo-c-driver-1.30.4/debian/patches/0002_CVE-2026-6231.patch 1970-01-01 00:00:00.000000000 +0000 +++ mongo-c-driver-1.30.4/debian/patches/0002_CVE-2026-6231.patch 2026-04-27 15:48:27.000000000 +0000 @@ -0,0 +1,1079 @@ +From 40b673787060a80ef7f4875ae776cb4731dadec9 Mon Sep 17 00:00:00 2001 +From: vector-of-bool +Date: Mon, 9 Jun 2025 10:05:58 -0600 +Subject: [PATCH] [CDRIVER-6017] BSON Validation Refactor (#2026) (Cherry-pick + for 1.30.x) (#2031) + +* [CDRIVER-6017] BSON Validation Refactor (#2026) + +* New BSON validation routine rewrite + +The new `bson_validate` implementation does not +make use of the error-prone `bson_visit` APIs. Instead, it is written +as a simple recursive validator. The new validator respects requests +for UTF-8 validation properly. + +* Stop validating at 1000 depth, preventing stack overflow +* Replace most BSON validation tests with generated ones + +The existing test cases used BSON files, and didn't have +any commentary on what they were actually testing. New test cases are +generated from a Python shorthand and contain the tested bytes inline, +with a distinct test case for each actual validation scenario. + +* Disable UTF-8 validation by default on CRUD APIs +* Document and tweak the value of BSON_VALIDATE_CORRUPT +* Add test cases related to the overlong null encoding +* Tweak JS scope validation to permit more obj keys +* Add a NEWS entry for validation changes. +* Allow `-private.h` headers to not include the prelude header + +--------- + +Co-authored-by: Kevin Albertson +Co-authored-by: Ezra Chung <88335979+eramongodb@users.noreply.github.com> +--- + .evergreen/scripts/check-preludes.py | 6 +- + src/libbson/NEWS | 15 + + src/libbson/doc/bson_validate_flags_t.rst | 3 + + src/libbson/src/bson/bson-types.h | 47 +- + src/libbson/src/bson/bson.c | 239 +- + src/libbson/src/bson/validate-private.h | 37 + + src/libbson/src/bson/validate.c | 569 ++++ + src/libbson/tests/test-bson.c | 496 +--- + src/libbson/tests/test-validate.generated.c | 2511 ++++++++++++++++++ + src/libbson/tests/validate-tests.py | 1479 +++++++++++ + src/libmongoc/CMakeLists.txt | 1 + + src/libmongoc/src/mongoc/mongoc-util.c | 21 +- + src/libmongoc/tests/test-libmongoc-main.c | 1 + + src/libmongoc/tests/test-mongoc-bulk.c | 22 +- + src/libmongoc/tests/test-mongoc-collection.c | 8 +- + src/libmongoc/tests/test-mongoc-cursor.c | 10 +- + 16 files changed, 4764 insertions(+), 701 deletions(-) + create mode 100644 src/libbson/src/bson/validate-private.h + create mode 100644 src/libbson/src/bson/validate.c + create mode 100644 src/libbson/tests/test-validate.generated.c + create mode 100644 src/libbson/tests/validate-tests.py + +diff --git a/src/libbson/doc/bson_validate_flags_t.rst b/src/libbson/doc/bson_validate_flags_t.rst +index 85140f0310..13607818f0 100644 +--- a/src/libbson/doc/bson_validate_flags_t.rst ++++ b/src/libbson/doc/bson_validate_flags_t.rst +@@ -19,6 +19,7 @@ Synopsis + BSON_VALIDATE_DOT_KEYS = (1 << 2), + BSON_VALIDATE_UTF8_ALLOW_NULL = (1 << 3), + BSON_VALIDATE_EMPTY_KEYS = (1 << 4), ++ BSON_VALIDATE_CORRUPT = (1 << 5), + } bson_validate_flags_t; + + Description +@@ -40,6 +41,8 @@ Each defined flag aside from ``BSON_VALIDATE_NONE`` describes an optional valida + * ``BSON_VALIDATE_DOLLAR_KEYS`` Prohibit keys that start with ``$`` outside of a "DBRef" subdocument. + * ``BSON_VALIDATE_DOT_KEYS`` Prohibit keys that contain ``.`` anywhere in the string. + * ``BSON_VALIDATE_EMPTY_KEYS`` Prohibit zero-length keys. ++* ``BSON_VALIDATE_CORRUPT`` is not a control flag, but is used as an error code ++ when a validation routine encounters corrupt BSON data. + + .. seealso:: + +diff --git a/src/libbson/src/bson/bson-types.h b/src/libbson/src/bson/bson-types.h +index ad8ba743d8..3a4fcea61a 100644 +--- a/src/libbson/src/bson/bson-types.h ++++ b/src/libbson/src/bson/bson-types.h +@@ -204,25 +204,54 @@ typedef struct { + + + /** +- * bson_validate_flags_t: ++ * @brief Flags and error codes for BSON validation functions. + * +- * This enumeration is used for validation of BSON documents. It allows +- * selective control on what you wish to validate. ++ * Pass these flags bits to control the behavior of the `bson_validate` family ++ * of functions. + * +- * %BSON_VALIDATE_NONE: No additional validation occurs. +- * %BSON_VALIDATE_UTF8: Check that strings are valid UTF-8. +- * %BSON_VALIDATE_DOLLAR_KEYS: Check that keys do not start with $. +- * %BSON_VALIDATE_DOT_KEYS: Check that keys do not contain a period. +- * %BSON_VALIDATE_UTF8_ALLOW_NULL: Allow NUL bytes in UTF-8 text. +- * %BSON_VALIDATE_EMPTY_KEYS: Prohibit zero-length field names ++ * Additionally, if validation fails, then the error code set on a `bson_error_t` ++ * will have the value corresponding to the reason that validation failed. + */ + typedef enum { ++ /** ++ * @brief No special validation behavior specified. ++ */ + BSON_VALIDATE_NONE = 0, ++ /** ++ * @brief Check that all text components of the BSON data are valid UTF-8. ++ * ++ * Note that this will also cause validation to reject valid text that contains ++ * a null character. This can be changed by also passing ++ * `BSON_VALIDATE_UTF8_ALLOW_NULL` ++ */ + BSON_VALIDATE_UTF8 = (1 << 0), ++ /** ++ * @brief Check that element keys do not begin with an ASCII dollar `$` ++ */ + BSON_VALIDATE_DOLLAR_KEYS = (1 << 1), ++ /** ++ * @brief Check that element keys do not contain an ASCII period `.` ++ */ + BSON_VALIDATE_DOT_KEYS = (1 << 2), ++ /** ++ * @brief If set then it is *not* an error for a UTF-8 string to contain ++ * embedded null characters. ++ * ++ * This has no effect unless `BSON_VALIDATE_UTF8` is also passed. ++ */ + BSON_VALIDATE_UTF8_ALLOW_NULL = (1 << 3), ++ /** ++ * @brief Check that no element key is a zero-length empty string. ++ */ + BSON_VALIDATE_EMPTY_KEYS = (1 << 4), ++ /** ++ * @brief This is not a flag that controls behavior, but is instead used to indicate ++ * that a BSON document is corrupted in some way. This is the value that will ++ * appear as an error code. ++ * ++ * Passing this as a flag has no effect. ++ */ ++ BSON_VALIDATE_CORRUPT = (1 << 5), + } bson_validate_flags_t; + + +diff --git a/src/libbson/src/bson/bson.c b/src/libbson/src/bson/bson.c +index bb6dbcfa5c..727994626b 100644 +--- a/src/libbson/src/bson/bson.c ++++ b/src/libbson/src/bson/bson.c +@@ -15,6 +15,7 @@ + */ + + ++#include + #include + #include + #include +@@ -34,29 +35,6 @@ + #endif + + +-typedef enum { +- BSON_VALIDATE_PHASE_START, +- BSON_VALIDATE_PHASE_TOP, +- BSON_VALIDATE_PHASE_LF_REF_KEY, +- BSON_VALIDATE_PHASE_LF_REF_UTF8, +- BSON_VALIDATE_PHASE_LF_ID_KEY, +- BSON_VALIDATE_PHASE_LF_DB_KEY, +- BSON_VALIDATE_PHASE_LF_DB_UTF8, +- BSON_VALIDATE_PHASE_NOT_DBREF, +-} bson_validate_phase_t; +- +- +-/* +- * Structures. +- */ +-typedef struct { +- bson_validate_flags_t flags; +- ssize_t err_offset; +- bson_validate_phase_t phase; +- bson_error_t error; +-} bson_validate_state_t; +- +- + /* + * Globals. + */ +@@ -2489,196 +2467,6 @@ bson_array_as_canonical_extended_json (const bson_t *bson, size_t *length) + } + + +-#define VALIDATION_ERR(_flag, _msg, ...) bson_set_error (&state->error, BSON_ERROR_INVALID, _flag, _msg, __VA_ARGS__) +- +-static bool +-_bson_iter_validate_utf8 (const bson_iter_t *iter, const char *key, size_t v_utf8_len, const char *v_utf8, void *data) +-{ +- bson_validate_state_t *state = data; +- bool allow_null; +- +- if ((state->flags & BSON_VALIDATE_UTF8)) { +- allow_null = !!(state->flags & BSON_VALIDATE_UTF8_ALLOW_NULL); +- +- if (!bson_utf8_validate (v_utf8, v_utf8_len, allow_null)) { +- state->err_offset = iter->off; +- VALIDATION_ERR (BSON_VALIDATE_UTF8, "invalid utf8 string for key \"%s\"", key); +- return true; +- } +- } +- +- if ((state->flags & BSON_VALIDATE_DOLLAR_KEYS)) { +- if (state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8) { +- state->phase = BSON_VALIDATE_PHASE_LF_ID_KEY; +- } else if (state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) { +- state->phase = BSON_VALIDATE_PHASE_NOT_DBREF; +- } +- } +- +- return false; +-} +- +- +-static void +-_bson_iter_validate_corrupt (const bson_iter_t *iter, void *data) +-{ +- bson_validate_state_t *state = data; +- +- state->err_offset = iter->err_off; +- VALIDATION_ERR (BSON_VALIDATE_NONE, "%s", "corrupt BSON"); +-} +- +- +-static bool +-_bson_iter_validate_before (const bson_iter_t *iter, const char *key, void *data) +-{ +- bson_validate_state_t *state = data; +- +- if ((state->flags & BSON_VALIDATE_EMPTY_KEYS)) { +- if (key[0] == '\0') { +- state->err_offset = iter->off; +- VALIDATION_ERR (BSON_VALIDATE_EMPTY_KEYS, "%s", "empty key"); +- return true; +- } +- } +- +- if ((state->flags & BSON_VALIDATE_DOLLAR_KEYS)) { +- if (key[0] == '$') { +- if (state->phase == BSON_VALIDATE_PHASE_LF_REF_KEY && strcmp (key, "$ref") == 0) { +- state->phase = BSON_VALIDATE_PHASE_LF_REF_UTF8; +- } else if (state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY && strcmp (key, "$id") == 0) { +- state->phase = BSON_VALIDATE_PHASE_LF_DB_KEY; +- } else if (state->phase == BSON_VALIDATE_PHASE_LF_DB_KEY && strcmp (key, "$db") == 0) { +- state->phase = BSON_VALIDATE_PHASE_LF_DB_UTF8; +- } else { +- state->err_offset = iter->off; +- VALIDATION_ERR (BSON_VALIDATE_DOLLAR_KEYS, "keys cannot begin with \"$\": \"%s\"", key); +- return true; +- } +- } else if (state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY || state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8 || +- state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) { +- state->err_offset = iter->off; +- VALIDATION_ERR (BSON_VALIDATE_DOLLAR_KEYS, "invalid key within DBRef subdocument: \"%s\"", key); +- return true; +- } else { +- state->phase = BSON_VALIDATE_PHASE_NOT_DBREF; +- } +- } +- +- if ((state->flags & BSON_VALIDATE_DOT_KEYS)) { +- if (strstr (key, ".")) { +- state->err_offset = iter->off; +- VALIDATION_ERR (BSON_VALIDATE_DOT_KEYS, "keys cannot contain \".\": \"%s\"", key); +- return true; +- } +- } +- +- return false; +-} +- +- +-static bool +-_bson_iter_validate_codewscope ( +- const bson_iter_t *iter, const char *key, size_t v_code_len, const char *v_code, const bson_t *v_scope, void *data) +-{ +- bson_validate_state_t *state = data; +- size_t offset = 0; +- +- BSON_UNUSED (key); +- BSON_UNUSED (v_code_len); +- BSON_UNUSED (v_code); +- +- if (!bson_validate (v_scope, state->flags, &offset)) { +- state->err_offset = iter->off + offset; +- VALIDATION_ERR (BSON_VALIDATE_NONE, "%s", "corrupt code-with-scope"); +- return false; +- } +- +- return true; +-} +- +- +-static bool +-_bson_iter_validate_document (const bson_iter_t *iter, const char *key, const bson_t *v_document, void *data); +- +- +-static const bson_visitor_t bson_validate_funcs = { +- _bson_iter_validate_before, +- NULL, /* visit_after */ +- _bson_iter_validate_corrupt, +- NULL, /* visit_double */ +- _bson_iter_validate_utf8, +- _bson_iter_validate_document, +- _bson_iter_validate_document, /* visit_array */ +- NULL, /* visit_binary */ +- NULL, /* visit_undefined */ +- NULL, /* visit_oid */ +- NULL, /* visit_bool */ +- NULL, /* visit_date_time */ +- NULL, /* visit_null */ +- NULL, /* visit_regex */ +- NULL, /* visit_dbpoint */ +- NULL, /* visit_code */ +- NULL, /* visit_symbol */ +- _bson_iter_validate_codewscope, +-}; +- +- +-static bool +-_bson_iter_validate_document (const bson_iter_t *iter, const char *key, const bson_t *v_document, void *data) +-{ +- bson_validate_state_t *state = data; +- bson_iter_t child; +- bson_validate_phase_t phase = state->phase; +- +- BSON_UNUSED (key); +- +- if (!bson_iter_init (&child, v_document)) { +- state->err_offset = iter->off; +- return true; +- } +- +- if (state->phase == BSON_VALIDATE_PHASE_START) { +- state->phase = BSON_VALIDATE_PHASE_TOP; +- } else { +- state->phase = BSON_VALIDATE_PHASE_LF_REF_KEY; +- } +- +- (void) bson_iter_visit_all (&child, &bson_validate_funcs, state); +- +- if (state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY || state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8 || +- state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) { +- if (state->err_offset <= 0) { +- state->err_offset = iter->off; +- } +- +- return true; +- } +- +- state->phase = phase; +- +- return false; +-} +- +- +-static void +-_bson_validate_internal (const bson_t *bson, bson_validate_state_t *state) +-{ +- bson_iter_t iter; +- +- state->err_offset = -1; +- state->phase = BSON_VALIDATE_PHASE_START; +- memset (&state->error, 0, sizeof state->error); +- +- if (!bson_iter_init (&iter, bson)) { +- state->err_offset = 0; +- VALIDATION_ERR (BSON_VALIDATE_NONE, "%s", "corrupt BSON"); +- } else { +- _bson_iter_validate_document (&iter, NULL, bson, state); +- } +-} +- +- + bool + bson_validate (const bson_t *bson, bson_validate_flags_t flags, size_t *offset) + { +@@ -2692,29 +2480,26 @@ bson_validate_with_error (const bson_t *bson, bson_validate_flags_t flags, bson_ + return bson_validate_with_error_and_offset (bson, flags, NULL, error); + } + +- + bool + bson_validate_with_error_and_offset (const bson_t *bson, + bson_validate_flags_t flags, + size_t *offset, + bson_error_t *error) + { +- bson_validate_state_t state; +- +- state.flags = flags; +- _bson_validate_internal (bson, &state); ++ BSON_ASSERT_PARAM (bson); ++ BSON_OPTIONAL_PARAM (offset); ++ BSON_OPTIONAL_PARAM (error); + +- if (state.err_offset >= 0) { +- if (offset) { +- *offset = (size_t) state.err_offset; +- } +- if (error) { +- memcpy (error, &state.error, sizeof *error); +- } +- return false; ++ size_t offset_local = 0; ++ if (!offset) { ++ offset = &offset_local; ++ } ++ bson_error_t error_local; ++ if (!error) { ++ error = &error_local; + } + +- return true; ++ return _bson_validate_impl_v2 (bson, flags, offset, error); + } + + +diff --git a/src/libbson/src/bson/validate-private.h b/src/libbson/src/bson/validate-private.h +new file mode 100644 +index 0000000000..8774a1e653 +--- /dev/null ++++ b/src/libbson/src/bson/validate-private.h +@@ -0,0 +1,37 @@ ++#ifndef BSON_VALIDATE_PRIVATE_H_INCLUDED ++#define BSON_VALIDATE_PRIVATE_H_INCLUDED ++ ++#include ++ ++enum { ++ /** ++ * @brief This compile-time constant represents the maximum document nesting ++ * depth permitted by the `bson_validate` family of functions. If the nesting ++ * depth exceeds this limit, the data will be rejected. ++ * ++ * This limit is intentionally larger than the default limit of MongoDB ++ * server, since we cannot anticipate what a libbson user might actually want ++ * to do with BSON, and to prevent accidentally rejecting data that the ++ * server might accept. The main purpose of this limit is to prevent stack ++ * overflow, not to reject invalid data. ++ */ ++ BSON_VALIDATION_MAX_NESTING_DEPTH = 1000, ++}; ++ ++/** ++ * @brief Private function backing the implementation of validation. ++ * ++ * Validation was previously defined in the overburdened `bson-iter.c`, but it ++ * is now defined in its own file. ++ * ++ * @param bson The document to validate. Must be non-null. ++ * @param flags Validation control flags ++ * @param offset Receives the offset at which validation failed. Must be non-null. ++ * @param error Receives the error describing why validation failed. Must be non-null. ++ * @return true If the given document has no validation errors ++ * @return false Otherwise ++ */ ++bool ++_bson_validate_impl_v2 (const bson_t *bson, bson_validate_flags_t flags, size_t *offset, bson_error_t *error); ++ ++#endif // BSON_VALIDATE_PRIVATE_H_INCLUDED +diff --git a/src/libbson/src/bson/validate.c b/src/libbson/src/bson/validate.c +new file mode 100644 +index 0000000000..10402df0c0 +--- /dev/null ++++ b/src/libbson/src/bson/validate.c +@@ -0,0 +1,569 @@ ++/** ++ * @file bson/validate.c ++ * @brief Implementation of BSON document validation ++ * @date 2025-05-28 ++ * ++ * This file implements the backend for the `bson_validate` family of functions. ++ * ++ * The `_validate_...` functions all accept `validator* self` as their first parameter, ++ * and must `return false` AND set `self->error` if-and-only-if they encounter a validation error. ++ * If a function returns true, it is assumed that validation of that item succeeded. ++ * ++ * For brevity, the `require...` macros are defined, which check conditions, set errors, ++ * and `return false` inline. ++ * ++ * @copyright Copyright 2009-present MongoDB, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++ ++/** ++ * @brief User parameters for validation behavior. These correspond to the various ++ * flags that can be given when the user requests validation ++ */ ++typedef struct { ++ /** ++ * @brief Should we allow invalid UTF-8 in string components? ++ * ++ * This affects the behavior of validation of key strings and string-like ++ * elements that require UTF-8 encoding. ++ * ++ * Technically invalid UTF-8 is invalid in BSON, but applications may already ++ * rely on this being accepted. ++ */ ++ bool allow_invalid_utf8; ++ /** ++ * @brief Should we allow a zero-valued codepoint in text? ++ * ++ * Unicode U+0000 is a valid codepoint, but a lot of software doesn't like ++ * it and handles it poorly. By default, we reject it, but the user may ++ * want to allow it. ++ * ++ * Note that because element keys rely on null termination, element keys ++ * cannot contain U+0000 by construction. ++ */ ++ bool allow_null_in_utf8; ++ /// Should we allow element key strings to be empty strings? ++ bool allow_empty_keys; ++ /// Should we allow ASCII dot "." in element key strings? ++ bool allow_dot_in_keys; ++ /** ++ * @brief Check for special element keys that begin with an ASCII dollar "$" ++ * ++ * By default, we ignore them and treat them as regular elements. If this is ++ * enabled, we reject key strings that start with a dollar, unless it is a ++ * special extended JSON DBRef document. ++ * ++ * This also enables DBRef validation, which checks the structure of a document ++ * whose first key is "$ref". ++ */ ++ bool check_special_dollar_keys; ++} validation_params; ++ ++/** ++ * @brief State for a validator. ++ */ ++typedef struct { ++ /// The parameters that control validation behavior ++ const validation_params *params; ++ /// Error storage that is updated if any validation encounters an error ++ bson_error_t error; ++ /// The zero-based index of the byte where validation stopped in case of an error. ++ size_t error_offset; ++} validator; ++ ++// Undef these macros, if they are defined. ++#ifdef require_with_error ++#undef require_with_error ++#endif ++#ifdef require ++#undef require ++#endif ++#ifdef require_advance ++#undef require_advance ++#endif ++ ++/** ++ * @brief Check that the given condition is satisfied, or set an error and return `false` ++ * ++ * @param Condition The condition that should evaluate to `true` ++ * @param Offset The byte offset where an error should be indicated. ++ * @param Code The error code that should be set if the condition fails ++ * @param ... The error string and format arguments to be used in the error message ++ * ++ * This macro assumes a `validator* self` is in scope. This macro will evaluate `return false` ++ * if the given condition is not true. ++ */ ++#define require_with_error(Condition, Offset, Code, ...) \ ++ if (!(Condition)) { \ ++ self->error_offset = (Offset); \ ++ bson_set_error (&self->error, BSON_ERROR_INVALID, Code, __VA_ARGS__); \ ++ return false; \ ++ } else \ ++ ((void) 0) ++ ++/** ++ * @brief Check that the given condition is satisfied, or `return false` immediately. ++ * ++ * This macro does not modify the validator state. It only does an early-return. ++ */ ++#define require(Cond) \ ++ if (!(Cond)) { \ ++ return false; \ ++ } else \ ++ ((void) 0) ++ ++/** ++ * @brief Advance the pointed-to iterator, check for errors, and test whether we are done. ++ * ++ * @param DoneVar An l-value of type `bool` that is set to `true` if the iterator hit the end of ++ * the document, otherwise `false` ++ * @param IteratorPointer An expression of type `bson_iter_t*`, which will be advanced. ++ * ++ * If advancing the iterator results in a decoding error, then this macro sets an error ++ * on the `validator* self` that is in scope and will immediately `return false`. ++ */ ++#define require_advance(DoneVar, IteratorPointer) \ ++ if ((DoneVar = !bson_iter_next (IteratorPointer))) { \ ++ /* The iterator indicates that it stopped */ \ ++ if ((IteratorPointer)->err_off) { \ ++ /* The iterator stopped because of a decoding error */ \ ++ require_with_error (false, (IteratorPointer)->err_off, BSON_VALIDATE_CORRUPT, "corrupt BSON"); \ ++ } \ ++ } else \ ++ ((void) 0) ++ ++// Test if the element's key is equal to the given string ++static bool ++_key_is (bson_iter_t const *iter, const char *const key) ++{ ++ BSON_ASSERT_PARAM (iter); ++ BSON_ASSERT_PARAM (key); ++ return !strcmp (bson_iter_key (iter), key); ++} ++ ++/** ++ * @brief Validate a document or array object, recursively. ++ * ++ * @param self The validator which will be updated and used to do the validation ++ * @param bson The object to be validated ++ * @param depth The validation depth. We indicate an error if this exceeds a limit. ++ * @return true If the object is valid ++ * @return false Otherwise ++ */ ++static bool ++_validate_doc (validator *self, const bson_t *bson, int depth); ++ ++/** ++ * @brief Validate a UTF-8 string, if-and-only-if UTF-8 validation is requested ++ * ++ * @param self Pointer to the validator object ++ * @param offset The byte-offset of the string, used to set the error offset ++ * @param u8 Pointer to the first byte in a UTF-8 string ++ * @param u8len The length of the array pointed-to by `u8` ++ * @return true If the UTF-8 string is valid, or if UTF-8 validation is disabled ++ * @return false If UTF-8 validation is requested, AND (the UTF-8 string is invalid OR (UTF-8 strings should not contain ++ * null characters and the UTF-8 string contains a null character)) ++ */ ++static bool ++_maybe_validate_utf8 (validator *self, size_t offset, const char *u8, size_t u8len) ++{ ++ BSON_ASSERT_PARAM (self); ++ BSON_ASSERT_PARAM (u8); ++ if (self->params->allow_invalid_utf8) { ++ // We are not doing UTF-8 checks, so always succeed ++ return true; ++ } ++ // Validate UTF-8 ++ const bool u8okay = bson_utf8_validate (u8, u8len, self->params->allow_null_in_utf8); ++ if (u8okay) { ++ // Valid UTF-8, no more checks ++ return true; ++ } ++ // Validation error. It may be invalid UTF-8, or it could be valid UTF-8 with a disallowed null ++ if (!self->params->allow_null_in_utf8) { ++ // We are disallowing null in UTF-8. Check whether it is invalid UTF-8, or is ++ // valid UTF-8 with a null character ++ const bool u8okay_with_null = bson_utf8_validate (u8, u8len, true); ++ if (u8okay_with_null) { ++ // The UTF-8 is valid, but contains a null character. ++ require_with_error ( ++ false, offset, BSON_VALIDATE_UTF8_ALLOW_NULL, "UTF-8 string contains a U+0000 (null) character"); ++ } ++ } ++ // The UTF-8 is invalid, regardless of whether it contains a null character ++ require_with_error (false, offset, BSON_VALIDATE_UTF8, "Text element is not valid UTF-8"); ++} ++ ++// Same as `_maybe_validate_u8`, but relies on a null-terminated C string to get the string length ++static bool ++_maybe_validate_utf8_cstring (validator *self, size_t offset, const char *const u8) ++{ ++ BSON_ASSERT_PARAM (self); ++ BSON_ASSERT_PARAM (u8); ++ return _maybe_validate_utf8 (self, offset, u8, strlen (u8)); ++} ++ ++/** ++ * @brief Validate a string-like element (UTF-8, Symbol, or Code) ++ * ++ * This function relies on the representation of the text-like elements within ++ * the iterator struct to reduce code dup around text validation. ++ */ ++static bool ++_validate_stringlike_element (validator *self, bson_iter_t const *iter) ++{ ++ BSON_ASSERT_PARAM (self); ++ BSON_ASSERT_PARAM (iter); ++ // iter->d1 is the offset to the string header. Subtract 1 to exclude the null terminator ++ uint32_t u8len; ++ memcpy (&u8len, iter->raw + iter->d1, sizeof u8len); ++ u8len = BSON_UINT32_FROM_LE (u8len); ++ u8len -= 1; ++ // iter->d2 is the offset to the first byte of the string ++ const char *u8 = (const char *) iter->raw + iter->d2; ++ return _maybe_validate_utf8 (self, iter->off, u8, u8len); ++} ++ ++static bool ++_validate_regex_elem (validator *self, bson_iter_t const *iter) ++{ ++ BSON_ASSERT_PARAM (self); ++ BSON_ASSERT_PARAM (iter); ++ BSON_ASSERT (BSON_ITER_HOLDS_REGEX (iter)); ++ const char *opts; ++ const char *const rx = bson_iter_regex (iter, &opts); ++ BSON_ASSERT (rx); ++ BSON_ASSERT (opts); ++ return _maybe_validate_utf8_cstring (self, iter->off, rx) // ++ && _maybe_validate_utf8_cstring (self, iter->off, opts); ++} ++ ++static bool ++_validate_codewscope_elem (validator *self, bson_iter_t const *iter, int depth) ++{ ++ BSON_ASSERT_PARAM (self); ++ BSON_ASSERT_PARAM (iter); ++ BSON_ASSERT (BSON_ITER_HOLDS_CODEWSCOPE (iter)); ++ // Extract the code and the scope object ++ uint8_t const *doc; ++ uint32_t doc_len; ++ uint32_t u8len; ++ const char *const u8 = bson_iter_codewscope (iter, &u8len, &doc_len, &doc); ++ bson_t scope; ++ require_with_error ( ++ bson_init_static (&scope, doc, doc_len), iter->off, BSON_VALIDATE_CORRUPT, "corrupt scope document"); ++ ++ // Validate the code string ++ require (_maybe_validate_utf8 (self, iter->off, u8, u8len)); ++ ++ // Now we validate the scope object. ++ // Don't validate the scope document using the parent parameters, because it should ++ // be treated as an opaque closure of JS variables. ++ validation_params const scope_params = { ++ // JS object keys can contain dots ++ .allow_dot_in_keys = true, ++ // JS object keys can be empty ++ .allow_empty_keys = true, ++ // JS strings can contain null bytes ++ .allow_null_in_utf8 = true, ++ // JS strings need to encode properly ++ .allow_invalid_utf8 = false, ++ // JS allows object keys to have dollars ++ .check_special_dollar_keys = false, ++ }; ++ validator scope_validator = {.params = &scope_params}; ++ // We could do more validation that the scope keys are valid JS identifiers, ++ // but that would require using a full Unicode database. ++ if (_validate_doc (&scope_validator, &scope, depth)) { ++ // No error ++ return true; ++ } ++ // Validation error. Copy the error message, adding the name of the bad element ++ bson_set_error (&self->error, ++ scope_validator.error.domain, ++ scope_validator.error.code, ++ "Error in scope document for element \"%s\": %s", ++ bson_iter_key (iter), ++ scope_validator.error.message); ++ // Adjust the error offset by the offset of the iterator ++ self->error_offset = scope_validator.error_offset + iter->off; ++ return false; ++} ++ ++// Validate an element's key string according to the validation rules ++static bool ++_validate_element_key (validator *self, bson_iter_t const *iter) ++{ ++ BSON_ASSERT_PARAM (self); ++ BSON_ASSERT_PARAM (iter); ++ ++ const char *const key = bson_iter_key (iter); ++ BSON_ASSERT (key); ++ const size_t key_len = bson_iter_key_len (iter); ++ ++ // Check the UTF-8 of the key ++ require (_maybe_validate_utf8 (self, iter->off, key, key_len)); ++ ++ // Check for special keys ++ if (self->params->check_special_dollar_keys) { ++ // dollar-keys are checked during the startup of _validate_doc. If we get here, there's a problem. ++ require_with_error ( ++ key[0] != '$', iter->off, BSON_VALIDATE_DOLLAR_KEYS, "Disallowed '$' in element key: \"%s\"", key); ++ } ++ ++ if (!self->params->allow_empty_keys) { ++ require_with_error (key_len != 0, iter->off, BSON_VALIDATE_EMPTY_KEYS, "Element key cannot be an empty string"); ++ } ++ ++ if (!self->params->allow_dot_in_keys) { ++ require_with_error ( ++ !strstr (key, "."), iter->off, BSON_VALIDATE_DOT_KEYS, "Disallowed '.' in element key: \"%s\"", key); ++ } ++ ++ return true; ++} ++ ++// Extract a document referred-to by the given iterator. It must point to a ++// document or array element. Returns `false` if `bson_init_static` returns false ++static bool ++_get_subdocument (bson_t *subdoc, bson_iter_t const *iter) ++{ ++ BSON_ASSERT_PARAM (subdoc); ++ BSON_ASSERT_PARAM (iter); ++ uint32_t len; ++ memcpy (&len, iter->raw + iter->d1, sizeof len); ++ len = BSON_UINT32_FROM_LE (len); ++ uint8_t const *data = (uint8_t const *) iter->raw + iter->d1; ++ return bson_init_static (subdoc, data, len); ++} ++ ++// Validate the value of an element, without checking its key ++static bool ++_validate_element_value (validator *self, bson_iter_t const *iter, int depth) ++{ ++ BSON_ASSERT_PARAM (self); ++ BSON_ASSERT_PARAM (iter); ++ ++ const bson_type_t type = bson_iter_type (iter); ++ switch (type) { ++ default: ++ case BSON_TYPE_EOD: ++ BSON_UNREACHABLE ("Validation execution encountered an element of type 0x0, but this should not happen as tag " ++ "validation is handled before we get to this point."); ++ case BSON_TYPE_DOUBLE: ++ case BSON_TYPE_NULL: ++ case BSON_TYPE_OID: ++ case BSON_TYPE_INT32: ++ case BSON_TYPE_INT64: ++ case BSON_TYPE_MINKEY: ++ case BSON_TYPE_MAXKEY: ++ case BSON_TYPE_TIMESTAMP: ++ case BSON_TYPE_UNDEFINED: ++ case BSON_TYPE_DECIMAL128: ++ case BSON_TYPE_DATE_TIME: ++ case BSON_TYPE_BOOL: ++ // No validation on these simple scalar elements. `bson_iter_next` does validation ++ // on these objects for us. ++ return true; ++ case BSON_TYPE_BINARY: ++ // Note: BSON binary validation is handled by bson_iter_next, which checks the ++ // internal structure properly. If we get here, then the binary data is okay. ++ return true; ++ case BSON_TYPE_DBPOINTER: ++ // DBPointer contains more than just a string, but we only need to validate ++ // the string component, which happens to align with the repr of other stringlike ++ // elements. bson_iter_next will do the validation on the element's size. ++ //! fallthrough ++ case BSON_TYPE_SYMBOL: ++ case BSON_TYPE_CODE: ++ case BSON_TYPE_UTF8: ++ return _validate_stringlike_element (self, iter); ++ case BSON_TYPE_DOCUMENT: ++ case BSON_TYPE_ARRAY: { ++ bson_t doc; ++ require_with_error (_get_subdocument (&doc, iter), iter->off, BSON_VALIDATE_CORRUPT, "corrupt BSON"); ++ if (_validate_doc (self, &doc, depth)) { ++ // No error ++ return true; ++ } ++ // Error in subdocument. Adjust the error offset for the current iterator position, ++ // plus the key length, plus 2 for the tag and key's null terminator. ++ self->error_offset += iter->off + bson_iter_key_len (iter) + 2; ++ return false; ++ } ++ ++ case BSON_TYPE_REGEX: ++ return _validate_regex_elem (self, iter); ++ case BSON_TYPE_CODEWSCOPE: ++ return _validate_codewscope_elem (self, iter, depth); ++ } ++} ++ ++// Validate a single BSON element referred-to by the given iterator ++static bool ++_validate_element (validator *self, bson_iter_t *iter, int depth) ++{ ++ BSON_ASSERT_PARAM (self); ++ BSON_ASSERT_PARAM (iter); ++ return _validate_element_key (self, iter) && _validate_element_value (self, iter, depth); ++} ++ ++/** ++ * @brief Validate the elements of a document, beginning with the element pointed-to ++ * by the given iterator. ++ */ ++static bool ++_validate_remaining_elements (validator *self, bson_iter_t *iter, int depth) ++{ ++ BSON_ASSERT_PARAM (self); ++ BSON_ASSERT_PARAM (iter); ++ bool done = false; ++ while (!done) { ++ require (_validate_element (self, iter, depth)); ++ require_advance (done, iter); ++ } ++ return true; ++} ++ ++// Do validation for a DBRef document, indicated by a leading $ref key ++static bool ++_validate_dbref (validator *self, bson_iter_t *iter, int depth) ++{ ++ BSON_ASSERT_PARAM (self); ++ BSON_ASSERT_PARAM (iter); ++ ++ // The iterator must be pointing to the initial $ref element ++ BSON_ASSERT (_key_is (iter, "$ref")); ++ // Check that $ref is a UTF-8 element ++ require_with_error ( ++ BSON_ITER_HOLDS_UTF8 (iter), iter->off, BSON_VALIDATE_DOLLAR_KEYS, "$ref element must be a UTF-8 element"); ++ require (_validate_element_value (self, iter, depth)); ++ ++ // We require an $id as the next element ++ bool done; ++ require_advance (done, iter); ++ require_with_error ( ++ !done && _key_is (iter, "$id"), iter->off, BSON_VALIDATE_DOLLAR_KEYS, "Expected an $id element following $ref"); ++ // While $id is typically a OID value, it is not constraint to any specific type, so ++ // we just validate it as an arbitrary value. ++ require (_validate_element_value (self, iter, depth)); ++ ++ // We should stop, or we should have a $db, or we may have other elements ++ require_advance (done, iter); ++ if (done) { ++ // No more elements. Nothing left to check ++ return true; ++ } ++ // If it's a $db, check that it's a UTF-8 string ++ if (_key_is (iter, "$db")) { ++ require_with_error (BSON_ITER_HOLDS_UTF8 (iter), ++ iter->off, ++ BSON_VALIDATE_DOLLAR_KEYS, ++ "$db element in DBRef must be a UTF-8 element"); ++ require (_validate_element_value (self, iter, depth)); ++ // Advance past the $db ++ require_advance (done, iter); ++ if (done) { ++ // Nothing left to do ++ return true; ++ } ++ } ++ // All subsequent elements should be validated as normal, and we don't expect ++ // any more $-keys ++ return _validate_remaining_elements (self, iter, depth); ++} ++ ++// If we are validating special $-keys, validate a document whose first element is a $-key ++static bool ++_validate_dollar_doc (validator *self, bson_iter_t *iter, int depth) ++{ ++ BSON_ASSERT_PARAM (self); ++ BSON_ASSERT_PARAM (iter); ++ if (_key_is (iter, "$ref")) { ++ return _validate_dbref (self, iter, depth); ++ } ++ // Have the element key validator issue an error message about the bad $-key ++ bool okay = _validate_element_key (self, iter); ++ BSON_ASSERT (!okay); ++ return false; ++} ++ ++static bool ++_validate_doc (validator *self, const bson_t *bson, int depth) ++{ ++ BSON_ASSERT_PARAM (self); ++ BSON_ASSERT_PARAM (bson); ++ ++ require_with_error ( ++ depth <= BSON_VALIDATION_MAX_NESTING_DEPTH, 0, BSON_VALIDATE_CORRUPT, "BSON document nesting depth is too deep"); ++ // We increment the depth here, otherwise we'd have `depth + 1` in several places. ++ ++depth; ++ ++ // Initialize an iterator into the document to be validated ++ bson_iter_t iter; ++ require_with_error ( ++ bson_iter_init (&iter, bson), 0, BSON_VALIDATE_CORRUPT, "Document header corruption, unable to iterate"); ++ bool done; ++ require_advance (done, &iter); ++ if (done) { ++ // Nothing to check (empty doc/array) ++ return true; ++ } ++ ++ // Check if the first key starts with a dollar ++ if (self->params->check_special_dollar_keys) { ++ const char *const key = bson_iter_key (&iter); ++ if (key[0] == '$') { ++ return _validate_dollar_doc (self, &iter, depth); ++ } ++ } ++ ++ return _validate_remaining_elements (self, &iter, depth); ++} ++ ++// This private function is called by `bson_validate_with_error_and_offset` ++bool ++_bson_validate_impl_v2 (const bson_t *bson, bson_validate_flags_t flags, size_t *offset, bson_error_t *error) ++{ ++ BSON_ASSERT_PARAM (bson); ++ BSON_ASSERT_PARAM (offset); ++ BSON_ASSERT_PARAM (error); ++ ++ // Clear the error ++ *error = (bson_error_t){0}; ++ ++ // Initialize validation parameters ++ validation_params const params = { ++ .allow_invalid_utf8 = !(flags & BSON_VALIDATE_UTF8), ++ .allow_null_in_utf8 = flags & BSON_VALIDATE_UTF8_ALLOW_NULL, ++ .check_special_dollar_keys = (flags & BSON_VALIDATE_DOLLAR_KEYS), ++ .allow_dot_in_keys = !(flags & BSON_VALIDATE_DOT_KEYS), ++ .allow_empty_keys = !(flags & BSON_VALIDATE_EMPTY_KEYS), ++ }; ++ ++ // Start the validator on the root document ++ validator v = {.params = ¶ms}; ++ bool okay = _validate_doc (&v, bson, 0); ++ *offset = v.error_offset; ++ *error = v.error; ++ BSON_ASSERT (okay == (v.error.code == 0) && ++ "Validation routine should return `false` if-and-only-if it sets an error code"); ++ return okay; ++} +diff --git a/src/libmongoc/src/mongoc/mongoc-util.c b/src/libmongoc/src/mongoc/mongoc-util.c +index a83d8c5146..37306c4c20 100644 +--- a/src/libmongoc/src/mongoc/mongoc-util.c ++++ b/src/libmongoc/src/mongoc/mongoc-util.c +@@ -33,14 +33,19 @@ + #include + #include + +-const bson_validate_flags_t _mongoc_default_insert_vflags = +- BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL | BSON_VALIDATE_EMPTY_KEYS; +- +-const bson_validate_flags_t _mongoc_default_replace_vflags = +- BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL | BSON_VALIDATE_EMPTY_KEYS; +- +-const bson_validate_flags_t _mongoc_default_update_vflags = +- BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL | BSON_VALIDATE_EMPTY_KEYS; ++/** ++ * ! NOTE ++ * ++ * In earlier releases, these flags had `BSON_VALIDATE_UTF8` and `BSON_VALIDATE_UTF8_ALLOW_NULL`. ++ * Due to a bug, the CRUD APIs did not actually do UTF-8 validation. This issue has been fixed, but ++ * we want to maintain backward compatibility, so the UTF-8 validation was removed from these flag ++ * values. ++ * ++ * A future API may add the UTF-8 validation back, but it would be a breaking change. ++ */ ++const bson_validate_flags_t _mongoc_default_insert_vflags = BSON_VALIDATE_EMPTY_KEYS; ++const bson_validate_flags_t _mongoc_default_replace_vflags = BSON_VALIDATE_EMPTY_KEYS; ++const bson_validate_flags_t _mongoc_default_update_vflags = BSON_VALIDATE_EMPTY_KEYS; + + int + _mongoc_rand_simple (unsigned int *seed) +-- +2.39.5 + diff -Nru mongo-c-driver-1.30.4/debian/patches/0003_CVE-2026-6231.patch mongo-c-driver-1.30.4/debian/patches/0003_CVE-2026-6231.patch --- mongo-c-driver-1.30.4/debian/patches/0003_CVE-2026-6231.patch 1970-01-01 00:00:00.000000000 +0000 +++ mongo-c-driver-1.30.4/debian/patches/0003_CVE-2026-6231.patch 2026-04-27 15:48:27.000000000 +0000 @@ -0,0 +1,27 @@ +From 017e630199cd006e01288b241774168b7d2b8bdf Mon Sep 17 00:00:00 2001 +From: Kevin Albertson +Date: Mon, 9 Jun 2025 15:16:57 -0400 +Subject: [PATCH] [CDRIVER-6017] Reduce `BSON_VALIDATION_MAX_NESTING_DEPTH` to + 500 (#2035) + +To fix stack overflow encountered on MSVC on r1.30 branch. Likely caused by default over-alignment of `bson_t` and `bson_iter_t` removed in 2.0. +--- + src/libbson/src/bson/validate-private.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libbson/src/bson/validate-private.h b/src/libbson/src/bson/validate-private.h +index 8774a1e653..f6c8e664ff 100644 +--- a/src/libbson/src/bson/validate-private.h ++++ b/src/libbson/src/bson/validate-private.h +@@ -15,7 +15,7 @@ enum { + * server might accept. The main purpose of this limit is to prevent stack + * overflow, not to reject invalid data. + */ +- BSON_VALIDATION_MAX_NESTING_DEPTH = 1000, ++ BSON_VALIDATION_MAX_NESTING_DEPTH = 500, + }; + + /** +-- +2.39.5 + diff -Nru mongo-c-driver-1.30.4/debian/patches/0004_CVE-2026-4359.patch mongo-c-driver-1.30.4/debian/patches/0004_CVE-2026-4359.patch --- mongo-c-driver-1.30.4/debian/patches/0004_CVE-2026-4359.patch 1970-01-01 00:00:00.000000000 +0000 +++ mongo-c-driver-1.30.4/debian/patches/0004_CVE-2026-4359.patch 2026-04-27 15:48:27.000000000 +0000 @@ -0,0 +1,36 @@ +From 754232f3cffe924346dcf327f4a723f1a0839420 Mon Sep 17 00:00:00 2001 +From: Remi Collet +Date: Thu, 19 Mar 2026 13:07:46 +0100 +Subject: [PATCH] CDRIVER-6251 fix handling of HTTP response (#2233) (#2234) + (#2254) + +(cherry picked from commit b93ebe6b99e614b49a24316c7a295eb3f08af603) + +Co-authored-by: Kevin Albertson +--- + src/libmongoc/src/mongoc/mongoc-http.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/libmongoc/src/mongoc/mongoc-http.c b/src/libmongoc/src/mongoc/mongoc-http.c +index 9284162a17..ec65031eee 100644 +--- a/src/libmongoc/src/mongoc/mongoc-http.c ++++ b/src/libmongoc/src/mongoc/mongoc-http.c +@@ -213,6 +213,15 @@ _mongoc_http_send (const mongoc_http_request_t *req, + goto fail; + } + ++ // Ensure NULL terminator follows content ++ { ++ if (!_mongoc_buffer_append(&http_response_buf, (const uint8_t[]){0u}, 1)) { ++ bson_set_error(error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to buffer HTTP response"); ++ goto fail; ++ } ++ http_response_buf.len--; ++ } ++ + http_response_str = (char *) http_response_buf.data; + const char *const resp_end_ptr = http_response_str + http_response_buf.len; + +-- +2.39.5 + diff -Nru mongo-c-driver-1.30.4/debian/patches/0005_CDRIVER-6281.patch mongo-c-driver-1.30.4/debian/patches/0005_CDRIVER-6281.patch --- mongo-c-driver-1.30.4/debian/patches/0005_CDRIVER-6281.patch 1970-01-01 00:00:00.000000000 +0000 +++ mongo-c-driver-1.30.4/debian/patches/0005_CDRIVER-6281.patch 2026-04-27 15:48:27.000000000 +0000 @@ -0,0 +1,92 @@ +From f70634e1d6d084f3b0f7077d03bde2d4cb95ce37 Mon Sep 17 00:00:00 2001 +From: Kevin Albertson +Date: Fri, 3 Apr 2026 21:16:37 -0400 +Subject: [PATCH] CDRIVER-6281 improve handling of corrupt GridFS files (#2263) + +* add regression test for 0 chunk size + +* check chunkSize on read + +* propagate error in `mongoc_gridfs_file_list_next` + +* add regression test for too-small chunk + +* fix too-small chunk read +--- + .../src/mongoc/mongoc-gridfs-file-list.c | 7 +- + .../src/mongoc/mongoc-gridfs-file-page.c | 4 + + src/libmongoc/src/mongoc/mongoc-gridfs-file.c | 10 +- + src/libmongoc/tests/test-mongoc-gridfs.c | 110 ++++++++++++++++++ + 4 files changed, 127 insertions(+), 4 deletions(-) + +diff --git a/src/libmongoc/src/mongoc/mongoc-gridfs-file-list.c b/src/libmongoc/src/mongoc/mongoc-gridfs-file-list.c +index f0b4b19339..058e30d28b 100644 +--- a/src/libmongoc/src/mongoc/mongoc-gridfs-file-list.c ++++ b/src/libmongoc/src/mongoc/mongoc-gridfs-file-list.c +@@ -99,7 +99,12 @@ mongoc_gridfs_file_list_next (mongoc_gridfs_file_list_t *list) + BSON_ASSERT (list); + + if (mongoc_cursor_next (list->cursor, &bson)) { +- return _mongoc_gridfs_file_new_from_bson (list->gridfs, bson); ++ mongoc_gridfs_file_t *file = _mongoc_gridfs_file_new_from_bson (list->gridfs, bson); ++ if (!file) { ++ bson_set_error ( ++ &list->cursor->error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CORRUPT, "Failed to read GridFS file"); ++ } ++ return file; + } else { + return NULL; + } +diff --git a/src/libmongoc/src/mongoc/mongoc-gridfs-file-page.c b/src/libmongoc/src/mongoc/mongoc-gridfs-file-page.c +index 161cc32c3c..7606406791 100644 +--- a/src/libmongoc/src/mongoc/mongoc-gridfs-file-page.c ++++ b/src/libmongoc/src/mongoc/mongoc-gridfs-file-page.c +@@ -72,6 +72,10 @@ _mongoc_gridfs_file_page_read (mongoc_gridfs_file_page_t *page, void *dst, uint3 + BSON_ASSERT (page); + BSON_ASSERT (dst); + ++ if (page->offset > page->len) { ++ RETURN (-1); ++ } ++ + bytes_read = BSON_MIN (len, page->len - page->offset); + + src = page->read_buf ? page->read_buf : page->buf; +diff --git a/src/libmongoc/src/mongoc/mongoc-gridfs-file.c b/src/libmongoc/src/mongoc/mongoc-gridfs-file.c +index 78384f4bf9..c10d7e50ff 100644 +--- a/src/libmongoc/src/mongoc/mongoc-gridfs-file.c ++++ b/src/libmongoc/src/mongoc/mongoc-gridfs-file.c +@@ -234,7 +234,8 @@ _mongoc_gridfs_file_new_from_bson (mongoc_gridfs_t *gridfs, const bson_t *data) + if (!BSON_ITER_HOLDS_NUMBER (&iter)) { + GOTO (failure); + } +- if (bson_iter_as_int64 (&iter) > INT32_MAX) { ++ int64_t as_i64 = bson_iter_as_int64 (&iter); ++ if (as_i64 > INT32_MAX || as_i64 <= 0) { + GOTO (failure); + } + file->chunk_size = (int32_t) bson_iter_as_int64 (&iter); +@@ -284,7 +285,7 @@ _mongoc_gridfs_file_new_from_bson (mongoc_gridfs_t *gridfs, const bson_t *data) + + failure: + bson_destroy (&file->bson); +- ++ bson_free (file); + RETURN (NULL); + } + +@@ -450,7 +451,10 @@ mongoc_gridfs_file_readv ( + for (;;) { + r = _mongoc_gridfs_file_page_read ( + file->page, (uint8_t *) iov[i].iov_base + iov_pos, (uint32_t) (iov[i].iov_len - iov_pos)); +- BSON_ASSERT (r >= 0); ++ if (r < 0) { ++ bson_set_error (&file->error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CORRUPT, "GridFS operation failed"); ++ return -1; ++ } + + iov_pos += r; + file->pos += r; +-- +2.39.5 + diff -Nru mongo-c-driver-1.30.4/debian/patches/0006_CVE-2025-14911.patch mongo-c-driver-1.30.4/debian/patches/0006_CVE-2025-14911.patch --- mongo-c-driver-1.30.4/debian/patches/0006_CVE-2025-14911.patch 1970-01-01 00:00:00.000000000 +0000 +++ mongo-c-driver-1.30.4/debian/patches/0006_CVE-2025-14911.patch 2026-04-27 15:48:27.000000000 +0000 @@ -0,0 +1,56 @@ +From ed8bed47906e37dd27306de0095ccbc56d6ec906 Mon Sep 17 00:00:00 2001 +From: Kevin Albertson +Date: Thu, 16 Oct 2025 14:41:21 -0400 +Subject: [PATCH] CDRIVER-6125 fix GridFS chunk size handling (#2146) (#2150) + +* validate chunk size from server document +* test negative and zero length +* check for negative length + * Not strictly needed. But gives an earlier error. +--- + .../src/mongoc/mongoc-gridfs-bucket.c | 21 +++ + .../tests/test-mongoc-gridfs-bucket.c | 175 ++++++++++++++++++ + 2 files changed, 196 insertions(+) + +diff --git a/src/libmongoc/src/mongoc/mongoc-gridfs-bucket.c b/src/libmongoc/src/mongoc/mongoc-gridfs-bucket.c +index 27bd3ed1af..8439f46df5 100644 +--- a/src/libmongoc/src/mongoc/mongoc-gridfs-bucket.c ++++ b/src/libmongoc/src/mongoc/mongoc-gridfs-bucket.c +@@ -179,6 +179,7 @@ mongoc_gridfs_bucket_open_upload_stream_with_id (mongoc_gridfs_bucket_t *bucket, + file->bucket = bucket; + file->chunk_size = gridfs_opts.chunkSizeBytes; + file->metadata = bson_copy (&gridfs_opts.metadata); ++ BSON_ASSERT (gridfs_opts.chunkSizeBytes > 0); // Validated in _mongoc_gridfs_bucket_opts_parse. + file->buffer = bson_malloc ((size_t) gridfs_opts.chunkSizeBytes); + file->in_buffer = 0; + +@@ -344,6 +345,26 @@ mongoc_gridfs_bucket_open_download_stream (mongoc_gridfs_bucket_t *bucket, + + bson_destroy (&file_doc); + ++ if (file->chunk_size <= 0) { ++ _mongoc_set_error (error, ++ MONGOC_ERROR_GRIDFS, ++ MONGOC_ERROR_GRIDFS_CORRUPT, ++ "File document contains invalid chunk size: %" PRId32, ++ file->chunk_size); ++ _mongoc_gridfs_bucket_file_destroy (file); ++ return NULL; ++ } ++ ++ if (file->length < 0) { ++ _mongoc_set_error (error, ++ MONGOC_ERROR_GRIDFS, ++ MONGOC_ERROR_GRIDFS_CORRUPT, ++ "File document contains invalid length: %" PRId64, ++ file->length); ++ _mongoc_gridfs_bucket_file_destroy (file); ++ return NULL; ++ } ++ + file->file_id = (bson_value_t *) bson_malloc0 (sizeof *(file->file_id)); + bson_value_copy (file_id, file->file_id); + file->bucket = bucket; +-- +2.39.5 + diff -Nru mongo-c-driver-1.30.4/debian/patches/0007_CVE-2025-14911.patch mongo-c-driver-1.30.4/debian/patches/0007_CVE-2025-14911.patch --- mongo-c-driver-1.30.4/debian/patches/0007_CVE-2025-14911.patch 1970-01-01 00:00:00.000000000 +0000 +++ mongo-c-driver-1.30.4/debian/patches/0007_CVE-2025-14911.patch 2026-04-27 15:48:27.000000000 +0000 @@ -0,0 +1,49 @@ +From bc7645f3a5dea3bd9c4c31d83713cb67978a57d9 Mon Sep 17 00:00:00 2001 +From: Kevin Albertson +Date: Tue, 7 Apr 2026 09:34:54 -0400 +Subject: [PATCH] CDRIVER-6125 replace `_mongoc_set_error` with + `bson_set_error` + +--- + .../src/mongoc/mongoc-gridfs-bucket.c | 20 +++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/src/libmongoc/src/mongoc/mongoc-gridfs-bucket.c b/src/libmongoc/src/mongoc/mongoc-gridfs-bucket.c +index 8439f46df5..656e55897f 100644 +--- a/src/libmongoc/src/mongoc/mongoc-gridfs-bucket.c ++++ b/src/libmongoc/src/mongoc/mongoc-gridfs-bucket.c +@@ -346,21 +346,21 @@ mongoc_gridfs_bucket_open_download_stream (mongoc_gridfs_bucket_t *bucket, + bson_destroy (&file_doc); + + if (file->chunk_size <= 0) { +- _mongoc_set_error (error, +- MONGOC_ERROR_GRIDFS, +- MONGOC_ERROR_GRIDFS_CORRUPT, +- "File document contains invalid chunk size: %" PRId32, +- file->chunk_size); ++ bson_set_error (error, ++ MONGOC_ERROR_GRIDFS, ++ MONGOC_ERROR_GRIDFS_CORRUPT, ++ "File document contains invalid chunk size: %" PRId32, ++ file->chunk_size); + _mongoc_gridfs_bucket_file_destroy (file); + return NULL; + } + + if (file->length < 0) { +- _mongoc_set_error (error, +- MONGOC_ERROR_GRIDFS, +- MONGOC_ERROR_GRIDFS_CORRUPT, +- "File document contains invalid length: %" PRId64, +- file->length); ++ bson_set_error (error, ++ MONGOC_ERROR_GRIDFS, ++ MONGOC_ERROR_GRIDFS_CORRUPT, ++ "File document contains invalid length: %" PRId64, ++ file->length); + _mongoc_gridfs_bucket_file_destroy (file); + return NULL; + } +-- +2.39.5 + diff -Nru mongo-c-driver-1.30.4/debian/patches/0008_CVE-2026-6691.patch mongo-c-driver-1.30.4/debian/patches/0008_CVE-2026-6691.patch --- mongo-c-driver-1.30.4/debian/patches/0008_CVE-2026-6691.patch 1970-01-01 00:00:00.000000000 +0000 +++ mongo-c-driver-1.30.4/debian/patches/0008_CVE-2026-6691.patch 2026-04-27 15:48:27.000000000 +0000 @@ -0,0 +1,39 @@ +From d2519ea8a403861782d9cde05c71c265bb568bbc Mon Sep 17 00:00:00 2001 +From: Kevin Albertson +Date: Fri, 24 Oct 2025 13:11:50 -0400 +Subject: [PATCH] CDRIVER-6134 check SASL username length + +Cherry-pick b4984965877d559862e225beba09cb4e9d4a56a6 and d9c26f49e75d3de746a690db9c81ff5b4f6e21b0 and reformat. +--- + src/libmongoc/src/mongoc/mongoc-cyrus.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/src/libmongoc/src/mongoc/mongoc-cyrus.c b/src/libmongoc/src/mongoc/mongoc-cyrus.c +index 10b5dc138a..d4125594b3 100644 +--- a/src/libmongoc/src/mongoc/mongoc-cyrus.c ++++ b/src/libmongoc/src/mongoc/mongoc-cyrus.c +@@ -112,10 +112,19 @@ _mongoc_cyrus_canon_user (sasl_conn_t *conn, + BSON_UNUSED (sasl); + BSON_UNUSED (flags); + BSON_UNUSED (user_realm); +- BSON_UNUSED (out_max); ++ ++ // `inlen` is a string length (excluding trailing NULL). ++ // Cyrus-SASL passes an `out` buffer of size `out_max + 1`. Assume `out_max` is the max to be safe. ++ const unsigned inlen_2 = inlen + 2u; ++ if (inlen_2 < inlen || inlen_2 >= out_max) { ++ MONGOC_ERROR ("SASL username too large"); ++ return SASL_BUFOVER; ++ } + + TRACE ("Canonicalizing %s (%" PRIu32 ")\n", in, inlen); +- strcpy (out, in); ++ // Use memmove in case buffers overlap. From Cyrus-SASL: "output buffers and the input buffers may be the same" ++ memmove (out, in, inlen); ++ out[inlen] = '\0'; + *out_len = inlen; + return SASL_OK; + } +-- +2.39.5 + diff -Nru mongo-c-driver-1.30.4/debian/patches/series mongo-c-driver-1.30.4/debian/patches/series --- mongo-c-driver-1.30.4/debian/patches/series 2025-12-18 19:50:07.000000000 +0000 +++ mongo-c-driver-1.30.4/debian/patches/series 2026-04-27 15:48:27.000000000 +0000 @@ -1,2 +1,9 @@ 0001_local_mathjax.diff CVE-2025-12119.patch +0002_CVE-2026-6231.patch +0003_CVE-2026-6231.patch +0004_CVE-2026-4359.patch +0005_CDRIVER-6281.patch +0006_CVE-2025-14911.patch +0007_CVE-2025-14911.patch +0008_CVE-2026-6691.patch