CVE-2022-3510 (Other, published 2022-12-12T13:15Z)
Description: value: A parsing issue similar to CVE-2022-3171, but with Message-Type Extensions in protobuf-java core and lite versions prior to 3.21.7, 3.20.3, 3.19.6 and 3.16.3 can lead to a denial of service attack. Inputs containing multiple instances of non-repeated embedded messages with repeated or unknown fields causes objects to be converted back-n-forth between mutable and immutable forms, resulting in potentially long garbage collection pauses. We recommend updating to the versions mentioned above.


Severity: nan (CVSS v3 base score: 7.5)
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/protocolbuffers/protobuf
Files changed:
CHANGES.txt
java/core/src/main/java/com/google/protobuf/MessageReflection.java
ruby/compatibility_tests/v3.0.0/tests/basic.rb
ruby/ext/google/protobuf_c/message.c
ruby/src/main/java/com/google/protobuf/jruby/RubyEnumDescriptor.java
ruby/tests/basic_test.proto
ruby/tests/basic_test_proto2.proto
ruby/tests/common_tests.rb
ruby/tests/generated_code.proto
ruby/tests/generated_code_proto2.proto
ruby/tests/repeated_field_test.rb
Commit message: Sync from Piper @mkruskal/footmitten

PROTOBUF_SYNC_PIPER


Vulnerable code:
-  * Refactoring java full runtime to reuse sub-message builders and prepare to migrate parsing logic from parse constructor to builder.
           input.readGroup(field.getNumber(), builder.getFieldBuilder(field), extensionRegistry);
           return;
         Message.Builder subBuilder = newMessageFieldInstance(field, defaultInstance);
           input.readMessage(builder.getFieldBuilder(field), extensionRegistry);
           return;
         Message.Builder subBuilder = newMessageFieldInstance(field, defaultInstance);
-      if (defaultInstance != null) {
-        subBuilder = defaultInstance.newBuilderForType();
-      } else {
-        subBuilder = builder.newBuilderForField(field);
-      return builder.buildPartial();
-      m["z"] = 4
-      assert m["z"] == 4
-    const char* name = upb_EnumValueDef_Name(ev);
-      rb_warn(
-      String name = value.getName();
-      // Make sure its a valid constant name before trying to create it
-      if (Character.isUpperCase(name.codePointAt(0))) {
-    assert l.count == 3
-    l.push 4
-    assert l[3] == 4
-    m["z"] = 4
-    assert m["z"] == 4
-  
-  

Fixed code:
+  * Refactoring java full runtime to reuse sub-message builders and prepare to
+    migrate parsing logic from parse constructor to builder.
+  * Move proto wireformat parsing functionality from the private "parsing
+    constructor" to the Builder class.
+  * Change the Lite runtime to prefer merging from the wireformat into mutable
+    messages rather than building up a new immutable object before merging. This
+    way results in fewer allocations and copy operations.
+  * Make message-type extensions merge from wire-format instead of building up instances and merging afterwards. This has much better performance.
+    private boolean hasNestedBuilders = true;
+    private Message.Builder getFieldBuilder(Descriptors.FieldDescriptor field) {
+      if (hasNestedBuilders) {
+        try {
+          return builder.getFieldBuilder(field);
+        } catch (UnsupportedOperationException e) {
+          hasNestedBuilders = false;
+        }
+      }
+      return null;
+    }
+
+      if (!field.isRepeated() && value instanceof MessageLite.Builder) {
+        if (value != getFieldBuilder(field)) {
+          builder.setField(field, ((MessageLite.Builder) value).buildPartial());
+        }
+        return this;
+      }
+      if (value instanceof MessageLite.Builder) {
+        value = ((MessageLite.Builder) value).buildPartial();
+      }
+      if (value instanceof MessageLite.Builder) {
+        value = ((MessageLite.Builder) value).buildPartial();
+      }
+        Message.Builder subBuilder;
+          subBuilder = getFieldBuilder(field);
+          if (subBuilder != null) {
+            input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
+            return;
+          } else {
+            subBuilder = newMessageFieldInstance(field, defaultInstance);
+            subBuilder.mergeFrom((Message) getField(field));
+          }
+        } else {
+          subBuilder = newMessageFieldInstance(field, defaultInstance);
+        Message.Builder subBuilder;
+          subBuilder = getFieldBuilder(field);
+          if (subBuilder != null) {
+            input.readMessage(subBuilder, extensionRegistry);
+            return;
+          } else {
+            subBuilder = newMessageFieldInstance(field, defaultInstance);
+            subBuilder.mergeFrom((Message) getField(field));
+          }
+        } else {
+          subBuilder = newMessageFieldInstance(field, defaultInstance);
+      if (!field.isRepeated() && hasField(field)) {
+        subBuilder = getFieldBuilder(field);
+        if (subBuilder != null) {
+          return new BuilderAdapter(subBuilder);
+        }
+
+      subBuilder = newMessageFieldInstance(field, defaultInstance);
+      return builder;
+      m["z"] = 5
+      assert m["z"] == 5
+    char* name = strdup(upb_EnumValueDef_Name(ev));
+      if (name[0] >= 'a' && name[0] <= 'z') {
+        name[0] -= 32; // auto capitalize
+      } else {
+        rb_warn(
+      }
+    free(name);
+      String name = fixEnumConstantName(value.getName());
+      // Make sure it's a valid constant name before trying to create it
+      int ch = name.codePointAt(0);
+      if (Character.isUpperCase(ch)) {
+  private static String fixEnumConstantName(String name) {
+    if (name != null && name.length() > 0) {
+      int ch = name.codePointAt(0);
+      if (ch >= 'a' && ch <= 'z') {
+        // Protobuf enums can start with lowercase letters, while Ruby's constant should
+        // always start with uppercase letters. We tolerate this case by capitalizing
+        // the first character if possible.
+        return new StringBuilder()
+                .appendCodePoint(Character.toUpperCase(ch))
+                .append(name.substring(1))
+                .toString();
+      }
+    }
+    return name;
+  }
+
+  v0 = 4;
+  v0 = 4;
+    l.push :v0
+    assert l.count == 4
+    assert l[3] == :v0
+    l.push 5
+    assert l[4] == 5
+    m["z"] = 5
+    assert m["z"] == 5
+    assert proto_module::TestEnum::V0 == 4
+    assert proto_module::TestEnum::lookup(4) == :v0
+    assert proto_module::TestEnum::resolve(:v0) == 4
+
+
+
+  v0 = 4;
+
+  v0 = 4;
+      value :v0, 4