CVE-2022-3509 (Java, published 2022-12-12T13:15Z)
Description: value: A parsing issue similar to CVE-2022-3171, but with textformat 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
Commit message: Clean up TextFormat parser (#10673)

* Fix TextFormat parser

Vulnerable code:
  * Make message-type extensions merge from wire-format instead of building up instances and merging afterwards. This has much better performance.
          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();

Fixed code:
  * Make message-type extensions merge from wire-format instead of building up
    instances and merging afterwards. This has much better performance.
  * Fix TextFormat parser to build up recurring (but supposedly not repeated)
    sub-messages directly from text rather than building a new sub-message and
    merging the fully formed message into the existing field.
    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;