diff --git a/SPECS/mysql/CVE-2026-0994.patch b/SPECS/mysql/CVE-2026-0994.patch new file mode 100644 index 00000000000..da653566adc --- /dev/null +++ b/SPECS/mysql/CVE-2026-0994.patch @@ -0,0 +1,173 @@ +From 5ebddcb1bcbe51d1fe323baa145e85f4f23128cf Mon Sep 17 00:00:00 2001 +From: zhangskz +Date: Thu, 29 Jan 2026 16:32:56 -0500 +Subject: [PATCH] Fix Any recursion depth bypass in Python + json_format.ParseDict (#25239) (#25587) + +This fixes a security vulnerability where nested google.protobuf.Any messages could bypass the max_recursion_depth limit, potentially leading to denial of service via stack overflow. + +The root cause was that _ConvertAnyMessage() was calling itself recursively via methodcaller() for nested well-known types, bypassing the recursion depth tracking in ConvertMessage(). + +The fix routes well-known type parsing through ConvertMessage() to ensure proper recursion depth accounting for all message types including nested Any. + +Fixes #25070 + +Closes #25239 + +COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/25239 from aviralgarg05:fix-any-recursion-depth-bypass 3cbbcbea142593d3afd2ceba2db14b05660f62f4 +PiperOrigin-RevId: 862740421 + +Co-authored-by: Aviral Garg + +Upstream Patch Reference: https://github.com/protocolbuffers/protobuf/commit/5ebddcb1bcbe51d1fe323baa145e85f4f23128cf.patch +--- + .../protobuf/internal/json_format_test.py | 102 ++++++++++++++++++ + .../python/google/protobuf/json_format.py | 12 ++- + 2 files changed, 111 insertions(+), 3 deletions(-) + +diff --git a/extra/protobuf/protobuf-24.4/python/google/protobuf/internal/json_format_test.py b/extra/protobuf/protobuf-24.4/python/google/protobuf/internal/json_format_test.py +index b4f516d8..d2967801 100644 +--- a/extra/protobuf/protobuf-24.4/python/google/protobuf/internal/json_format_test.py ++++ b/extra/protobuf/protobuf-24.4/python/google/protobuf/internal/json_format_test.py +@@ -1297,6 +1297,108 @@ class JsonFormatTest(JsonFormatBase): + # The following one can pass + json_format.Parse('{"payload": {}, "child": {"child":{}}}', + message, max_recursion_depth=3) ++ ++ def testAnyRecursionDepthEnforcement(self): ++ """Test that nested Any messages respect max_recursion_depth limit.""" ++ # Test that deeply nested Any messages raise ParseError instead of ++ # bypassing the recursion limit. This prevents DoS via nested Any. ++ message = any_pb2.Any() ++ ++ # Create nested Any structure that should exceed depth limit ++ # With max_recursion_depth=5, we can nest 4 Any messages ++ # (depth 1 = outer Any, depth 2-4 = nested Anys, depth 5 = final value) ++ nested_any = { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': {}, ++ }, ++ }, ++ }, ++ }, ++ } ++ ++ # Should raise ParseError due to exceeding max depth, not RecursionError ++ self.assertRaisesRegex( ++ json_format.ParseError, ++ 'Message too deep. Max recursion depth is 5', ++ json_format.ParseDict, ++ nested_any, ++ message, ++ max_recursion_depth=5, ++ ) ++ ++ # Verify that Any messages within the limit can be parsed successfully ++ # With max_recursion_depth=5, we can nest up to 4 Any messages ++ shallow_any = { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': {}, ++ }, ++ }, ++ }, ++ } ++ json_format.ParseDict(shallow_any, message, max_recursion_depth=5) ++ ++ def testAnyRecursionDepthBoundary(self): ++ """Test recursion depth boundary behavior (exclusive upper limit).""" ++ message = any_pb2.Any() ++ ++ # Create nested Any at depth exactly 4 (should succeed with max_recursion_depth=5) ++ depth_4_any = { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': {}, ++ }, ++ }, ++ }, ++ } ++ # This should succeed: depth 4 < max_recursion_depth 5 ++ json_format.ParseDict(depth_4_any, message, max_recursion_depth=5) ++ ++ # Create nested Any at depth exactly 5 (should fail with max_recursion_depth=5) ++ depth_5_any = { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': { ++ '@type': 'type.googleapis.com/google.protobuf.Any', ++ 'value': {}, ++ }, ++ }, ++ }, ++ }, ++ } ++ # This should fail: depth 5 == max_recursion_depth 5 (exclusive limit) ++ self.assertRaisesRegex( ++ json_format.ParseError, ++ 'Message too deep. Max recursion depth is 5', ++ json_format.ParseDict, ++ depth_5_any, ++ message, ++ max_recursion_depth=5, ++ ) ++ + + if __name__ == '__main__': + unittest.main() +diff --git a/extra/protobuf/protobuf-24.4/python/google/protobuf/json_format.py b/extra/protobuf/protobuf-24.4/python/google/protobuf/json_format.py +index a04e8aef..2fe8da64 100644 +--- a/extra/protobuf/protobuf-24.4/python/google/protobuf/json_format.py ++++ b/extra/protobuf/protobuf-24.4/python/google/protobuf/json_format.py +@@ -496,6 +496,10 @@ class _Parser(object): + Raises: + ParseError: In case of convert problems. + """ ++ # Increment recursion depth at message entry. The max_recursion_depth limit ++ # is exclusive: a depth value equal to max_recursion_depth will trigger an ++ # error. For example, with max_recursion_depth=5, nesting up to depth 4 is ++ # allowed, but attempting depth 5 raises ParseError. + self.recursion_depth += 1 + if self.recursion_depth > self.max_recursion_depth: + raise ParseError('Message too deep. Max recursion depth is {0}'.format( +@@ -669,9 +673,11 @@ class _Parser(object): + self._ConvertWrapperMessage(value['value'], sub_message, + '{0}.value'.format(path)) + elif full_name in _WKTJSONMETHODS: +- methodcaller(_WKTJSONMETHODS[full_name][1], value['value'], sub_message, +- '{0}.value'.format(path))( +- self) ++ # For well-known types (including nested Any), use ConvertMessage ++ # to ensure recursion depth is properly tracked ++ self.ConvertMessage( ++ value['value'], sub_message, '{0}.value'.format(path) ++ ) + else: + del value['@type'] + self._ConvertFieldValuePair(value, sub_message, path) +-- +2.45.4 + diff --git a/SPECS/mysql/mysql.spec b/SPECS/mysql/mysql.spec index b53d2ed9567..a473d9c5cdd 100644 --- a/SPECS/mysql/mysql.spec +++ b/SPECS/mysql/mysql.spec @@ -1,7 +1,7 @@ Summary: MySQL. Name: mysql Version: 8.0.45 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2 with exceptions AND LGPLv2 AND BSD Vendor: Microsoft Corporation Distribution: Mariner @@ -15,6 +15,7 @@ Patch1: CVE-2024-2410.patch # ciphers unavailable. Patch2: fix-tests-for-unsupported-chacha-ciphers.patch Patch3: CVE-2025-62813.patch +Patch4: CVE-2026-0994.patch BuildRequires: cmake BuildRequires: libtirpc-devel BuildRequires: openssl-devel @@ -115,6 +116,9 @@ fi %{_libdir}/pkgconfig/mysqlclient.pc %changelog +* Mon Feb 09 2026 Jyoti Kanase - 8.0.45-2 +- Patch for CVE-2026-0994 + * Wed Jan 21 2026 Kanishk Bansal - 8.0.45-1 - Upgrade to 8.0.45 for CVE-2026-21948, CVE-2026-21968, CVE-2026-21941, CVE-2026-21964, CVE-2026-21936, CVE-2026-21937