diff mbox series

[meta-oe,scarthgap,1/2] protobuf: upgrade from 4.25.3 to 4.25.8

Message ID 20250624030600.986551-1-Qi.Chen@windriver.com
State New
Headers show
Series [meta-oe,scarthgap,1/2] protobuf: upgrade from 4.25.3 to 4.25.8 | expand

Commit Message

ChenQi June 24, 2025, 3:05 a.m. UTC
From: Chen Qi <Qi.Chen@windriver.com>

0001-Add-recursion-check-when-parsing-unknown-fields-in-J.patch is
dropped because it has been in new version.

This upgrade also fixes CVE-2025-4565. The fix commit is as below:

  d31100c91 Manually backport recursion limit enforcement to 25.x

Signed-off-by: Chen Qi <Qi.Chen@windriver.com>
---
 ...eck-when-parsing-unknown-fields-in-J.patch | 794 ------------------
 ...{protobuf_4.25.3.bb => protobuf_4.25.8.bb} |   3 +-
 2 files changed, 1 insertion(+), 796 deletions(-)
 delete mode 100644 meta-oe/recipes-devtools/protobuf/protobuf/0001-Add-recursion-check-when-parsing-unknown-fields-in-J.patch
 rename meta-oe/recipes-devtools/protobuf/{protobuf_4.25.3.bb => protobuf_4.25.8.bb} (97%)
diff mbox series

Patch

diff --git a/meta-oe/recipes-devtools/protobuf/protobuf/0001-Add-recursion-check-when-parsing-unknown-fields-in-J.patch b/meta-oe/recipes-devtools/protobuf/protobuf/0001-Add-recursion-check-when-parsing-unknown-fields-in-J.patch
deleted file mode 100644
index 2f14620b4a..0000000000
--- a/meta-oe/recipes-devtools/protobuf/protobuf/0001-Add-recursion-check-when-parsing-unknown-fields-in-J.patch
+++ /dev/null
@@ -1,794 +0,0 @@ 
-From 9f182ae260cc60e8cc5417abbe9481821642afa0 Mon Sep 17 00:00:00 2001
-From: Protobuf Team Bot <protobuf-github-bot@google.com>
-Date: Tue, 17 Sep 2024 12:03:36 -0700
-Subject: [PATCH] Add recursion check when parsing unknown fields in Java.
-
-PiperOrigin-RevId: 675657198
-
-CVE: CVE-2024-7254
-
-Upstream-Status: Backport [ac9fb5b4c71b0dd80985b27684e265d1f03abf46]
-
-The original patch is adjusted to fit for the current version.
-
-Signed-off-by: Chen Qi <Qi.Chen@windriver.com>
----
- .../com/google/protobuf/ArrayDecoders.java    |  28 +++
- .../com/google/protobuf/CodedInputStream.java |  72 +++++-
- .../com/google/protobuf/MessageSchema.java    |   9 +-
- .../com/google/protobuf/MessageSetSchema.java |   2 +-
- .../google/protobuf/UnknownFieldSchema.java   |  28 ++-
- .../google/protobuf/CodedInputStreamTest.java | 159 ++++++++++++
- .../java/com/google/protobuf/LiteTest.java    | 232 ++++++++++++++++++
- 7 files changed, 514 insertions(+), 16 deletions(-)
-
-diff --git a/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java b/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
-index f3241de50..0f3d7de0d 100644
---- a/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
-+++ b/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
-@@ -26,6 +26,10 @@ final class ArrayDecoders {
- 
-   private ArrayDecoders() {
-   }
-+  static final int DEFAULT_RECURSION_LIMIT = 100;
-+
-+  @SuppressWarnings("NonFinalStaticField")
-+  private static volatile int recursionLimit = DEFAULT_RECURSION_LIMIT;
- 
-   /**
-    * A helper used to return multiple values in a Java function. Java doesn't natively support
-@@ -38,6 +42,7 @@ final class ArrayDecoders {
-     public long long1;
-     public Object object1;
-     public final ExtensionRegistryLite extensionRegistry;
-+    public int recursionDepth;
- 
-     Registers() {
-       this.extensionRegistry = ExtensionRegistryLite.getEmptyRegistry();
-@@ -245,7 +250,10 @@ final class ArrayDecoders {
-     if (length < 0 || length > limit - position) {
-       throw InvalidProtocolBufferException.truncatedMessage();
-     }
-+    registers.recursionDepth++;
-+    checkRecursionLimit(registers.recursionDepth);
-     schema.mergeFrom(msg, data, position, position + length, registers);
-+    registers.recursionDepth--;
-     registers.object1 = msg;
-     return position + length;
-   }
-@@ -263,8 +271,11 @@ final class ArrayDecoders {
-     // A group field must has a MessageSchema (the only other subclass of Schema is MessageSetSchema
-     // and it can't be used in group fields).
-     final MessageSchema messageSchema = (MessageSchema) schema;
-+    registers.recursionDepth++;
-+    checkRecursionLimit(registers.recursionDepth);
-     final int endPosition =
-         messageSchema.parseMessage(msg, data, position, limit, endGroup, registers);
-+    registers.recursionDepth--;
-     registers.object1 = msg;
-     return endPosition;
-   }
-@@ -1025,6 +1036,8 @@ final class ArrayDecoders {
-         final UnknownFieldSetLite child = UnknownFieldSetLite.newInstance();
-         final int endGroup = (tag & ~0x7) | WireFormat.WIRETYPE_END_GROUP;
-         int lastTag = 0;
-+        registers.recursionDepth++;
-+        checkRecursionLimit(registers.recursionDepth);
-         while (position < limit) {
-           position = decodeVarint32(data, position, registers);
-           lastTag = registers.int1;
-@@ -1033,6 +1046,7 @@ final class ArrayDecoders {
-           }
-           position = decodeUnknownField(lastTag, data, position, limit, child, registers);
-         }
-+        registers.recursionDepth--;
-         if (position > limit || lastTag != endGroup) {
-           throw InvalidProtocolBufferException.parseFailure();
-         }
-@@ -1079,4 +1093,18 @@ final class ArrayDecoders {
-         throw InvalidProtocolBufferException.invalidTag();
-     }
-   }
-+
-+  /**
-+   * Set the maximum recursion limit that ArrayDecoders will allow. An exception will be thrown if
-+   * the depth of the message exceeds this limit.
-+   */
-+  public static void setRecursionLimit(int limit) {
-+    recursionLimit = limit;
-+  }
-+
-+  private static void checkRecursionLimit(int depth) throws InvalidProtocolBufferException {
-+    if (depth >= recursionLimit) {
-+      throw InvalidProtocolBufferException.recursionLimitExceeded();
-+    }
-+  }
- }
-diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
-index 8f1ac736d..29256b4b3 100644
---- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
-+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
-@@ -703,7 +703,14 @@ public abstract class CodedInputStream {
-     public void skipMessage() throws IOException {
-       while (true) {
-         final int tag = readTag();
--        if (tag == 0 || !skipField(tag)) {
-+	if (tag == 0) {
-+	    return;
-+	}
-+	checkRecursionLimit();
-+	++recursionDepth;
-+	boolean fieldSkipped = skipField(tag);
-+	--recursionDepth;
-+        if (!fieldSkipped) {
-           return;
-         }
-       }
-@@ -713,7 +720,14 @@ public abstract class CodedInputStream {
-     public void skipMessage(CodedOutputStream output) throws IOException {
-       while (true) {
-         final int tag = readTag();
--        if (tag == 0 || !skipField(tag, output)) {
-+	if (tag == 0) {
-+	    return;
-+	}
-+	checkRecursionLimit();
-+	++recursionDepth;
-+	boolean fieldSkipped = skipField(tag, output);
-+	--recursionDepth;
-+        if (!fieldSkipped) {
-           return;
-         }
-       }
-@@ -1415,7 +1429,14 @@ public abstract class CodedInputStream {
-     public void skipMessage() throws IOException {
-       while (true) {
-         final int tag = readTag();
--        if (tag == 0 || !skipField(tag)) {
-+	if (tag == 0) {
-+	    return;
-+	}
-+	checkRecursionLimit();
-+	++recursionDepth;
-+	boolean fieldSkipped = skipField(tag);
-+	--recursionDepth;
-+        if (!fieldSkipped) {
-           return;
-         }
-       }
-@@ -1425,7 +1446,14 @@ public abstract class CodedInputStream {
-     public void skipMessage(CodedOutputStream output) throws IOException {
-       while (true) {
-         final int tag = readTag();
--        if (tag == 0 || !skipField(tag, output)) {
-+	if (tag == 0) {
-+	    return;
-+	}
-+	checkRecursionLimit();
-+	++recursionDepth;
-+	boolean fieldSkipped = skipField(tag, output);
-+	--recursionDepth;
-+        if (!fieldSkipped) {
-           return;
-         }
-       }
-@@ -2180,7 +2208,14 @@ public abstract class CodedInputStream {
-     public void skipMessage() throws IOException {
-       while (true) {
-         final int tag = readTag();
--        if (tag == 0 || !skipField(tag)) {
-+	if (tag == 0) {
-+	    return;
-+	}
-+	checkRecursionLimit();
-+	++recursionDepth;
-+	boolean fieldSkipped = skipField(tag);
-+	--recursionDepth;
-+        if (!fieldSkipped) {
-           return;
-         }
-       }
-@@ -2190,7 +2225,14 @@ public abstract class CodedInputStream {
-     public void skipMessage(CodedOutputStream output) throws IOException {
-       while (true) {
-         final int tag = readTag();
--        if (tag == 0 || !skipField(tag, output)) {
-+	if (tag == 0) {
-+	    return;
-+	}
-+	checkRecursionLimit();
-+	++recursionDepth;
-+	boolean fieldSkipped = skipField(tag, output);
-+	--recursionDepth;
-+        if (!fieldSkipped) {
-           return;
-         }
-       }
-@@ -3298,7 +3340,14 @@ public abstract class CodedInputStream {
-     public void skipMessage() throws IOException {
-       while (true) {
-         final int tag = readTag();
--        if (tag == 0 || !skipField(tag)) {
-+	if (tag == 0) {
-+	    return;
-+	}
-+	checkRecursionLimit();
-+	++recursionDepth;
-+	boolean fieldSkipped = skipField(tag);
-+	--recursionDepth;
-+        if (!fieldSkipped) {
-           return;
-         }
-       }
-@@ -3308,7 +3357,14 @@ public abstract class CodedInputStream {
-     public void skipMessage(CodedOutputStream output) throws IOException {
-       while (true) {
-         final int tag = readTag();
--        if (tag == 0 || !skipField(tag, output)) {
-+	if (tag == 0) {
-+	    return;
-+	}
-+	checkRecursionLimit();
-+	++recursionDepth;
-+	boolean fieldSkipped = skipField(tag, output);
-+	--recursionDepth;
-+        if (!fieldSkipped) {
-           return;
-         }
-       }
-diff --git a/java/core/src/main/java/com/google/protobuf/MessageSchema.java b/java/core/src/main/java/com/google/protobuf/MessageSchema.java
-index de3890f70..5ad6762b0 100644
---- a/java/core/src/main/java/com/google/protobuf/MessageSchema.java
-+++ b/java/core/src/main/java/com/google/protobuf/MessageSchema.java
-@@ -3006,7 +3006,8 @@ final class MessageSchema<T> implements Schema<T> {
-               unknownFields = unknownFieldSchema.getBuilderFromMessage(message);
-             }
-             // Unknown field.
--            if (unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader)) {
-+            if (unknownFieldSchema.mergeOneFieldFrom(
-+                unknownFields, reader, /* currentDepth= */ 0)) {
-               continue;
-             }
-           }
-@@ -3381,7 +3382,8 @@ final class MessageSchema<T> implements Schema<T> {
-               if (unknownFields == null) {
-                 unknownFields = unknownFieldSchema.getBuilderFromMessage(message);
-               }
--              if (!unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader)) {
-+              if (!unknownFieldSchema.mergeOneFieldFrom(
-+                  unknownFields, reader, /* currentDepth= */ 0)) {
-                 return;
-               }
-               break;
-@@ -3397,7 +3399,8 @@ final class MessageSchema<T> implements Schema<T> {
-             if (unknownFields == null) {
-               unknownFields = unknownFieldSchema.getBuilderFromMessage(message);
-             }
--            if (!unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader)) {
-+            if (!unknownFieldSchema.mergeOneFieldFrom(
-+                unknownFields, reader, /* currentDepth= */ 0)) {
-               return;
-             }
-           }
-diff --git a/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java b/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
-index eec3acd35..ec37d41f9 100644
---- a/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
-+++ b/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
-@@ -278,7 +278,7 @@ final class MessageSetSchema<T> implements Schema<T> {
-               reader, extension, extensionRegistry, extensions);
-           return true;
-         } else {
--          return unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader);
-+          return unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader, /* currentDepth= */ 0);
-         }
-       } else {
-         return reader.skipField();
-diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
-index c4ec645bf..0cdecd30e 100644
---- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
-+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
-@@ -13,6 +13,11 @@ import java.io.IOException;
- @CheckReturnValue
- abstract class UnknownFieldSchema<T, B> {
- 
-+  static final int DEFAULT_RECURSION_LIMIT = 100;
-+
-+  @SuppressWarnings("NonFinalStaticField")
-+  private static volatile int recursionLimit = DEFAULT_RECURSION_LIMIT;
-+
-   /** Whether unknown fields should be dropped. */
-   abstract boolean shouldDiscardUnknownFields(Reader reader);
- 
-@@ -56,7 +61,8 @@ abstract class UnknownFieldSchema<T, B> {
-   abstract void makeImmutable(Object message);
- 
-   /** Merges one field into the unknown fields. */
--  final boolean mergeOneFieldFrom(B unknownFields, Reader reader) throws IOException {
-+  final boolean mergeOneFieldFrom(B unknownFields, Reader reader, int currentDepth)
-+      throws IOException {
-     int tag = reader.getTag();
-     int fieldNumber = WireFormat.getTagFieldNumber(tag);
-     switch (WireFormat.getTagWireType(tag)) {
-@@ -75,7 +81,12 @@ abstract class UnknownFieldSchema<T, B> {
-       case WireFormat.WIRETYPE_START_GROUP:
-         final B subFields = newBuilder();
-         int endGroupTag = WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
--        mergeFrom(subFields, reader);
-+        currentDepth++;
-+        if (currentDepth >= recursionLimit) {
-+          throw InvalidProtocolBufferException.recursionLimitExceeded();
-+        }
-+        mergeFrom(subFields, reader, currentDepth);
-+        currentDepth--;
-         if (endGroupTag != reader.getTag()) {
-           throw InvalidProtocolBufferException.invalidEndTag();
-         }
-@@ -88,10 +99,11 @@ abstract class UnknownFieldSchema<T, B> {
-     }
-   }
- 
--  final void mergeFrom(B unknownFields, Reader reader) throws IOException {
-+  final void mergeFrom(B unknownFields, Reader reader, int currentDepth)
-+      throws IOException {
-     while (true) {
-       if (reader.getFieldNumber() == Reader.READ_DONE
--          || !mergeOneFieldFrom(unknownFields, reader)) {
-+          || !mergeOneFieldFrom(unknownFields, reader, currentDepth)) {
-         break;
-       }
-     }
-@@ -108,4 +120,12 @@ abstract class UnknownFieldSchema<T, B> {
-   abstract int getSerializedSizeAsMessageSet(T message);
- 
-   abstract int getSerializedSize(T unknowns);
-+
-+  /**
-+   * Set the maximum recursion limit that ArrayDecoders will allow. An exception will be thrown if
-+   * the depth of the message exceeds this limit.
-+   */
-+  public void setRecursionLimit(int limit) {
-+    recursionLimit = limit;
-+  }
- }
-diff --git a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
-index 2de3273e3..19a6b669d 100644
---- a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
-+++ b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
-@@ -10,6 +10,10 @@ package com.google.protobuf;
- import static com.google.common.truth.Truth.assertThat;
- import static com.google.common.truth.Truth.assertWithMessage;
- import static org.junit.Assert.assertArrayEquals;
-+import static org.junit.Assert.assertThrows;
-+
-+import com.google.common.primitives.Bytes;
-+import map_test.MapTestProto.MapContainer;
- import protobuf_unittest.UnittestProto.BoolMessage;
- import protobuf_unittest.UnittestProto.Int32Message;
- import protobuf_unittest.UnittestProto.Int64Message;
-@@ -34,6 +38,13 @@ public class CodedInputStreamTest {
- 
-   private static final int DEFAULT_BLOCK_SIZE = 4096;
- 
-+  private static final int GROUP_TAP = WireFormat.makeTag(3, WireFormat.WIRETYPE_START_GROUP);
-+
-+  private static final byte[] NESTING_SGROUP = generateSGroupTags();
-+
-+  private static final byte[] NESTING_SGROUP_WITH_INITIAL_BYTES = generateSGroupTagsForMapField();
-+
-+
-   private enum InputType {
-     ARRAY {
-       @Override
-@@ -116,6 +127,17 @@ public class CodedInputStreamTest {
-     return bytes;
-   }
- 
-+  private static byte[] generateSGroupTags() {
-+    byte[] bytes = new byte[100000];
-+    Arrays.fill(bytes, (byte) GROUP_TAP);
-+    return bytes;
-+  }
-+
-+  private static byte[] generateSGroupTagsForMapField() {
-+    byte[] initialBytes = {18, 1, 75, 26, (byte) 198, (byte) 154, 12};
-+    return Bytes.concat(initialBytes, NESTING_SGROUP);
-+  }
-+
-   /**
-    * An InputStream which limits the number of bytes it reads at a time. We use this to make sure
-    * that CodedInputStream doesn't screw up when reading in small blocks.
-@@ -659,6 +681,143 @@ public class CodedInputStreamTest {
-     }
-   }
- 
-+  @Test
-+  public void testMaliciousRecursion_unknownFields() throws Exception {
-+    Throwable thrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class,
-+            () -> TestRecursiveMessage.parseFrom(NESTING_SGROUP));
-+
-+    assertThat(thrown).hasMessageThat().contains("Protocol message had too many levels of nesting");
-+  }
-+
-+  @Test
-+  public void testMaliciousRecursion_skippingUnknownField() throws Exception {
-+    Throwable thrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class,
-+            () ->
-+                DiscardUnknownFieldsParser.wrap(TestRecursiveMessage.parser())
-+                    .parseFrom(NESTING_SGROUP));
-+
-+    assertThat(thrown).hasMessageThat().contains("Protocol message had too many levels of nesting");
-+  }
-+
-+  @Test
-+  public void testMaliciousSGroupTagsWithMapField_fromInputStream() throws Exception {
-+    Throwable parseFromThrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class,
-+            () ->
-+                MapContainer.parseFrom(
-+                    new ByteArrayInputStream(NESTING_SGROUP_WITH_INITIAL_BYTES)));
-+    Throwable mergeFromThrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class,
-+            () ->
-+                MapContainer.newBuilder()
-+                    .mergeFrom(new ByteArrayInputStream(NESTING_SGROUP_WITH_INITIAL_BYTES)));
-+
-+    assertThat(parseFromThrown)
-+        .hasMessageThat()
-+        .contains("Protocol message had too many levels of nesting");
-+    assertThat(mergeFromThrown)
-+        .hasMessageThat()
-+        .contains("Protocol message had too many levels of nesting");
-+  }
-+
-+  @Test
-+  public void testMaliciousSGroupTags_inputStream_skipMessage() throws Exception {
-+    ByteArrayInputStream inputSteam = new ByteArrayInputStream(NESTING_SGROUP);
-+    CodedInputStream input = CodedInputStream.newInstance(inputSteam);
-+    CodedOutputStream output = CodedOutputStream.newInstance(new byte[NESTING_SGROUP.length]);
-+
-+    Throwable thrown = assertThrows(InvalidProtocolBufferException.class, input::skipMessage);
-+    Throwable thrown2 =
-+        assertThrows(InvalidProtocolBufferException.class, () -> input.skipMessage(output));
-+
-+    assertThat(thrown).hasMessageThat().contains("Protocol message had too many levels of nesting");
-+    assertThat(thrown2)
-+        .hasMessageThat()
-+        .contains("Protocol message had too many levels of nesting");
-+  }
-+
-+  @Test
-+  public void testMaliciousSGroupTagsWithMapField_fromByteArray() throws Exception {
-+    Throwable parseFromThrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class,
-+            () -> MapContainer.parseFrom(NESTING_SGROUP_WITH_INITIAL_BYTES));
-+    Throwable mergeFromThrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class,
-+            () -> MapContainer.newBuilder().mergeFrom(NESTING_SGROUP_WITH_INITIAL_BYTES));
-+
-+    assertThat(parseFromThrown)
-+        .hasMessageThat()
-+        .contains("the input ended unexpectedly in the middle of a field");
-+    assertThat(mergeFromThrown)
-+        .hasMessageThat()
-+        .contains("the input ended unexpectedly in the middle of a field");
-+  }
-+
-+  @Test
-+  public void testMaliciousSGroupTags_arrayDecoder_skipMessage() throws Exception {
-+    CodedInputStream input = CodedInputStream.newInstance(NESTING_SGROUP);
-+    CodedOutputStream output = CodedOutputStream.newInstance(new byte[NESTING_SGROUP.length]);
-+
-+    Throwable thrown = assertThrows(InvalidProtocolBufferException.class, input::skipMessage);
-+    Throwable thrown2 =
-+        assertThrows(InvalidProtocolBufferException.class, () -> input.skipMessage(output));
-+
-+    assertThat(thrown).hasMessageThat().contains("Protocol message had too many levels of nesting");
-+    assertThat(thrown2)
-+        .hasMessageThat()
-+        .contains("Protocol message had too many levels of nesting");
-+  }
-+
-+  @Test
-+  public void testMaliciousSGroupTagsWithMapField_fromByteBuffer() throws Exception {
-+    Throwable thrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class,
-+            () -> MapContainer.parseFrom(ByteBuffer.wrap(NESTING_SGROUP_WITH_INITIAL_BYTES)));
-+
-+    assertThat(thrown)
-+        .hasMessageThat()
-+        .contains("the input ended unexpectedly in the middle of a field");
-+  }
-+
-+  @Test
-+  public void testMaliciousSGroupTags_byteBuffer_skipMessage() throws Exception {
-+    CodedInputStream input = InputType.NIO_DIRECT.newDecoder(NESTING_SGROUP);
-+    CodedOutputStream output = CodedOutputStream.newInstance(new byte[NESTING_SGROUP.length]);
-+
-+    Throwable thrown = assertThrows(InvalidProtocolBufferException.class, input::skipMessage);
-+    Throwable thrown2 =
-+        assertThrows(InvalidProtocolBufferException.class, () -> input.skipMessage(output));
-+
-+    assertThat(thrown).hasMessageThat().contains("Protocol message had too many levels of nesting");
-+    assertThat(thrown2)
-+        .hasMessageThat()
-+        .contains("Protocol message had too many levels of nesting");
-+  }
-+
-+  @Test
-+  public void testMaliciousSGroupTags_iterableByteBuffer() throws Exception {
-+    CodedInputStream input = InputType.ITER_DIRECT.newDecoder(NESTING_SGROUP);
-+    CodedOutputStream output = CodedOutputStream.newInstance(new byte[NESTING_SGROUP.length]);
-+
-+    Throwable thrown = assertThrows(InvalidProtocolBufferException.class, input::skipMessage);
-+    Throwable thrown2 =
-+        assertThrows(InvalidProtocolBufferException.class, () -> input.skipMessage(output));
-+
-+    assertThat(thrown).hasMessageThat().contains("Protocol message had too many levels of nesting");
-+    assertThat(thrown2)
-+        .hasMessageThat()
-+        .contains("Protocol message had too many levels of nesting");
-+  }
-+
-   private void checkSizeLimitExceeded(InvalidProtocolBufferException e) {
-     assertThat(e)
-         .hasMessageThat()
-diff --git a/java/lite/src/test/java/com/google/protobuf/LiteTest.java b/java/lite/src/test/java/com/google/protobuf/LiteTest.java
-index 754ed7d5f..81be90bfd 100644
---- a/java/lite/src/test/java/com/google/protobuf/LiteTest.java
-+++ b/java/lite/src/test/java/com/google/protobuf/LiteTest.java
-@@ -2459,6 +2459,211 @@ public class LiteTest {
-     }
-   }
- 
-+  @Test
-+  public void testParseFromInputStream_concurrent_nestingUnknownGroups() throws Exception {
-+    int numThreads = 200;
-+    ArrayList<Thread> threads = new ArrayList<>();
-+
-+    ByteString byteString = generateNestingGroups(99);
-+    AtomicBoolean thrown = new AtomicBoolean(false);
-+
-+    for (int i = 0; i < numThreads; i++) {
-+      Thread thread =
-+          new Thread(
-+              () -> {
-+                try {
-+                  TestAllTypesLite unused = TestAllTypesLite.parseFrom(byteString);
-+                } catch (IOException e) {
-+                  if (e.getMessage().contains("Protocol message had too many levels of nesting")) {
-+                    thrown.set(true);
-+                  }
-+                }
-+              });
-+      thread.start();
-+      threads.add(thread);
-+    }
-+
-+    for (Thread thread : threads) {
-+      thread.join();
-+    }
-+
-+    assertThat(thrown.get()).isFalse();
-+  }
-+
-+  @Test
-+  public void testParseFromInputStream_nestingUnknownGroups() throws IOException {
-+    ByteString byteString = generateNestingGroups(99);
-+
-+    Throwable thrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class, () -> TestAllTypesLite.parseFrom(byteString));
-+    assertThat(thrown)
-+        .hasMessageThat()
-+        .doesNotContain("Protocol message had too many levels of nesting");
-+  }
-+
-+  @Test
-+  public void testParseFromInputStream_nestingUnknownGroups_exception() throws IOException {
-+    ByteString byteString = generateNestingGroups(100);
-+
-+    Throwable thrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class, () -> TestAllTypesLite.parseFrom(byteString));
-+    assertThat(thrown).hasMessageThat().contains("Protocol message had too many levels of nesting");
-+  }
-+
-+  @Test
-+  public void testParseFromInputStream_setRecursionLimit_exception() throws IOException {
-+    ByteString byteString = generateNestingGroups(199);
-+    UnknownFieldSchema<?, ?> schema = SchemaUtil.unknownFieldSetLiteSchema();
-+    schema.setRecursionLimit(200);
-+
-+    Throwable thrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class, () -> TestAllTypesLite.parseFrom(byteString));
-+    assertThat(thrown)
-+        .hasMessageThat()
-+        .doesNotContain("Protocol message had too many levels of nesting");
-+    schema.setRecursionLimit(UnknownFieldSchema.DEFAULT_RECURSION_LIMIT);
-+  }
-+
-+  @Test
-+  public void testParseFromBytes_concurrent_nestingUnknownGroups() throws Exception {
-+    int numThreads = 200;
-+    ArrayList<Thread> threads = new ArrayList<>();
-+
-+    ByteString byteString = generateNestingGroups(99);
-+    AtomicBoolean thrown = new AtomicBoolean(false);
-+
-+    for (int i = 0; i < numThreads; i++) {
-+      Thread thread =
-+          new Thread(
-+              () -> {
-+                try {
-+                  // Should pass in byte[] instead of ByteString to go into ArrayDecoders.
-+                  TestAllTypesLite unused = TestAllTypesLite.parseFrom(byteString.toByteArray());
-+                } catch (InvalidProtocolBufferException e) {
-+                  if (e.getMessage().contains("Protocol message had too many levels of nesting")) {
-+                    thrown.set(true);
-+                  }
-+                }
-+              });
-+      thread.start();
-+      threads.add(thread);
-+    }
-+
-+    for (Thread thread : threads) {
-+      thread.join();
-+    }
-+
-+    assertThat(thrown.get()).isFalse();
-+  }
-+
-+  @Test
-+  public void testParseFromBytes_nestingUnknownGroups() throws IOException {
-+    ByteString byteString = generateNestingGroups(99);
-+
-+    Throwable thrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class,
-+            () -> TestAllTypesLite.parseFrom(byteString.toByteArray()));
-+    assertThat(thrown)
-+        .hasMessageThat()
-+        .doesNotContain("Protocol message had too many levels of nesting");
-+  }
-+
-+  @Test
-+  public void testParseFromBytes_nestingUnknownGroups_exception() throws IOException {
-+    ByteString byteString = generateNestingGroups(100);
-+
-+    Throwable thrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class,
-+            () -> TestAllTypesLite.parseFrom(byteString.toByteArray()));
-+    assertThat(thrown).hasMessageThat().contains("Protocol message had too many levels of nesting");
-+  }
-+
-+  @Test
-+  public void testParseFromBytes_setRecursionLimit_exception() throws IOException {
-+    ByteString byteString = generateNestingGroups(199);
-+    ArrayDecoders.setRecursionLimit(200);
-+
-+    Throwable thrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class,
-+            () -> TestAllTypesLite.parseFrom(byteString.toByteArray()));
-+    assertThat(thrown)
-+        .hasMessageThat()
-+        .doesNotContain("Protocol message had too many levels of nesting");
-+    ArrayDecoders.setRecursionLimit(ArrayDecoders.DEFAULT_RECURSION_LIMIT);
-+  }
-+
-+  @Test
-+  public void testParseFromBytes_recursiveMessages() throws Exception {
-+    byte[] data99 = makeRecursiveMessage(99).toByteArray();
-+    byte[] data100 = makeRecursiveMessage(100).toByteArray();
-+
-+    RecursiveMessage unused = RecursiveMessage.parseFrom(data99);
-+    Throwable thrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class, () -> RecursiveMessage.parseFrom(data100));
-+    assertThat(thrown).hasMessageThat().contains("Protocol message had too many levels of nesting");
-+  }
-+
-+  @Test
-+  public void testParseFromBytes_recursiveKnownGroups() throws Exception {
-+    byte[] data99 = makeRecursiveGroup(99).toByteArray();
-+    byte[] data100 = makeRecursiveGroup(100).toByteArray();
-+
-+    RecursiveGroup unused = RecursiveGroup.parseFrom(data99);
-+    Throwable thrown =
-+        assertThrows(InvalidProtocolBufferException.class, () -> RecursiveGroup.parseFrom(data100));
-+    assertThat(thrown).hasMessageThat().contains("Protocol message had too many levels of nesting");
-+  }
-+
-+  @Test
-+  @SuppressWarnings("ProtoParseFromByteString")
-+  public void testMaliciousSGroupTagsWithMapField_fromByteArray() throws Exception {
-+    ByteString byteString = generateNestingGroups(102);
-+
-+    Throwable parseFromThrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class,
-+            () -> MapContainer.parseFrom(byteString.toByteArray()));
-+    Throwable mergeFromThrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class,
-+            () -> MapContainer.newBuilder().mergeFrom(byteString.toByteArray()));
-+
-+    assertThat(parseFromThrown)
-+        .hasMessageThat()
-+        .contains("Protocol message had too many levels of nesting");
-+    assertThat(mergeFromThrown)
-+        .hasMessageThat()
-+        .contains("Protocol message had too many levels of nesting");
-+  }
-+
-+  @Test
-+  public void testMaliciousSGroupTagsWithMapField_fromInputStream() throws Exception {
-+    byte[] bytes = generateNestingGroups(101).toByteArray();
-+
-+    Throwable parseFromThrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class,
-+            () -> MapContainer.parseFrom(new ByteArrayInputStream(bytes)));
-+    Throwable mergeFromThrown =
-+        assertThrows(
-+            InvalidProtocolBufferException.class,
-+            () -> MapContainer.newBuilder().mergeFrom(new ByteArrayInputStream(bytes)));
-+
-+    assertThat(parseFromThrown)
-+        .hasMessageThat()
-+        .contains("Protocol message had too many levels of nesting");
-+    assertThat(mergeFromThrown)
-+        .hasMessageThat()
-+        .contains("Protocol message had too many levels of nesting");
-+  }
-+
-   @Test
-   public void testParseFromByteBuffer_extensions() throws Exception {
-     TestAllExtensionsLite message =
-@@ -2815,4 +3020,31 @@ public class LiteTest {
-     }
-     return false;
-   }
-+
-+  private static ByteString generateNestingGroups(int num) throws IOException {
-+    int groupTap = WireFormat.makeTag(3, WireFormat.WIRETYPE_START_GROUP);
-+    ByteString.Output byteStringOutput = ByteString.newOutput();
-+    CodedOutputStream codedOutput = CodedOutputStream.newInstance(byteStringOutput);
-+    for (int i = 0; i < num; i++) {
-+      codedOutput.writeInt32NoTag(groupTap);
-+    }
-+    codedOutput.flush();
-+    return byteStringOutput.toByteString();
-+  }
-+
-+  private static RecursiveMessage makeRecursiveMessage(int num) {
-+    if (num == 0) {
-+      return RecursiveMessage.getDefaultInstance();
-+    } else {
-+      return RecursiveMessage.newBuilder().setRecurse(makeRecursiveMessage(num - 1)).build();
-+    }
-+  }
-+
-+  private static RecursiveGroup makeRecursiveGroup(int num) {
-+    if (num == 0) {
-+      return RecursiveGroup.getDefaultInstance();
-+    } else {
-+      return RecursiveGroup.newBuilder().setRecurse(makeRecursiveGroup(num - 1)).build();
-+    }
-+  }
- }
--- 
-2.25.1
-
diff --git a/meta-oe/recipes-devtools/protobuf/protobuf_4.25.3.bb b/meta-oe/recipes-devtools/protobuf/protobuf_4.25.8.bb
similarity index 97%
rename from meta-oe/recipes-devtools/protobuf/protobuf_4.25.3.bb
rename to meta-oe/recipes-devtools/protobuf/protobuf_4.25.8.bb
index acc35db4a5..949a3b207b 100644
--- a/meta-oe/recipes-devtools/protobuf/protobuf_4.25.3.bb
+++ b/meta-oe/recipes-devtools/protobuf/protobuf_4.25.8.bb
@@ -10,12 +10,11 @@  LIC_FILES_CHKSUM = "file://LICENSE;md5=37b5762e07f0af8c74ce80a8bda4266b"
 DEPENDS = "zlib abseil-cpp"
 DEPENDS:append:class-target = " protobuf-native"
 
-SRCREV = "4a2aef570deb2bfb8927426558701e8bfc26f2a4"
+SRCREV = "a4cbdd3ed0042e8f9b9c30e8b0634096d9532809"
 
 SRC_URI = "gitsm://github.com/protocolbuffers/protobuf.git;branch=25.x;protocol=https \
            file://run-ptest \
            file://0001-examples-Makefile-respect-CXX-LDFLAGS-variables-fix-.patch \
-           file://0001-Add-recursion-check-when-parsing-unknown-fields-in-J.patch \
            "
 SRC_URI:append:mips:toolchain-clang = " file://0001-Fix-build-on-mips-clang.patch "
 SRC_URI:append:mipsel:toolchain-clang = " file://0001-Fix-build-on-mips-clang.patch "