File protobuf-CVE-2026-0994.patch of Package protobuf.42475

--- a/python/google/protobuf/json_format.py
+++ b/python/google/protobuf/json_format.py
@@ -391,7 +391,13 @@ def _CreateMessageFromTypeUrl(type_url,
   return message_class()
 
 
-def Parse(text, message, ignore_unknown_fields=False, descriptor_pool=None):
+def Parse(
+    text,
+    message,
+    ignore_unknown_fields=False,
+    descriptor_pool=None,
+    max_recursion_depth=100,
+):
   """Parses a JSON representation of a protocol message into a message.
 
   Args:
@@ -400,6 +406,9 @@ def Parse(text, message, ignore_unknown_
     ignore_unknown_fields: If True, do not raise errors for unknown fields.
     descriptor_pool: A Descriptor Pool for resolving types. If None use the
         default.
+    max_recursion_depth: max recursion depth of JSON message to be deserialized.
+        JSON messages over this depth will fail to be deserialized. Default value
+        is 100.
 
   Returns:
     The same message passed as argument.
@@ -412,13 +421,25 @@ def Parse(text, message, ignore_unknown_
     js = json.loads(text, object_pairs_hook=_DuplicateChecker)
   except ValueError as e:
     raise ParseError('Failed to load JSON: {0}.'.format(str(e)))
-  return ParseDict(js, message, ignore_unknown_fields, descriptor_pool)
 
-
-def ParseDict(js_dict,
-              message,
-              ignore_unknown_fields=False,
-              descriptor_pool=None):
+  try:
+    return ParseDict(
+        js, message, ignore_unknown_fields, descriptor_pool, max_recursion_depth
+    )
+  except ParseError as e:
+    raise e
+  except Exception as e:
+    raise ParseError(
+        'Failed to parse JSON: {0}: {1}.'.format(type(e).__name__, str(e))
+    ) from e
+
+def ParseDict(
+    js_dict,
+    message,
+    ignore_unknown_fields=False,
+    descriptor_pool=None,
+    max_recursion_depth=100,
+):
   """Parses a JSON dictionary representation into a message.
 
   Args:
@@ -427,11 +448,14 @@ def ParseDict(js_dict,
     ignore_unknown_fields: If True, do not raise errors for unknown fields.
     descriptor_pool: A Descriptor Pool for resolving types. If None use the
       default.
+    max_recursion_depth: max recursion depth of JSON message to be deserialized.
+      JSON messages over this depth will fail to be deserialized. Default value
+      is 100.
 
   Returns:
     The same message passed as argument.
   """
-  parser = _Parser(ignore_unknown_fields, descriptor_pool)
+  parser = _Parser(ignore_unknown_fields, descriptor_pool, max_recursion_depth)
   parser.ConvertMessage(js_dict, message)
   return message
 
@@ -442,9 +466,13 @@ _INT_OR_FLOAT = six.integer_types + (flo
 class _Parser(object):
   """JSON format parser for protocol message."""
 
-  def __init__(self, ignore_unknown_fields, descriptor_pool):
+  def __init__(
+      self, ignore_unknown_fields, descriptor_pool, max_recursion_depth
+  ):
     self.ignore_unknown_fields = ignore_unknown_fields
     self.descriptor_pool = descriptor_pool
+    self.max_recursion_depth = max_recursion_depth
+    self.recursion_depth = 0
 
   def ConvertMessage(self, value, message):
     """Convert a JSON object into a message.
@@ -456,6 +484,17 @@ 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(
+              self.max_recursion_depth
+          )
+      )
     message_descriptor = message.DESCRIPTOR
     full_name = message_descriptor.full_name
     if _IsWrapperMessage(message_descriptor):
@@ -464,6 +503,7 @@ class _Parser(object):
       methodcaller(_WKTJSONMETHODS[full_name][1], value, message)(self)
     else:
       self._ConvertFieldValuePair(value, message)
+    self.recursion_depth -= 1
 
   def _ConvertFieldValuePair(self, js, message):
     """Convert field value pairs into regular message.
@@ -595,8 +635,9 @@ class _Parser(object):
     if _IsWrapperMessage(message_descriptor):
       self._ConvertWrapperMessage(value['value'], sub_message)
     elif full_name in _WKTJSONMETHODS:
-      methodcaller(
-          _WKTJSONMETHODS[full_name][1], value['value'], sub_message)(self)
+      # For well-known types (including nested Any), use ConvertMessage
+      # to ensure recursion depth is properly tracked
+      self.ConvertMessage(value['value'], sub_message)
     else:
       del value['@type']
       self._ConvertFieldValuePair(value, sub_message)
openSUSE Build Service is sponsored by