From 7c3e7a6d5ddca67cddb1c493620c38a32dc36463 Mon Sep 17 00:00:00 2001 From: Chen Qi Date: Tue, 24 Jun 2025 11:05:59 +0800 Subject: [PATCH] protobuf: upgrade from 4.25.3 to 4.25.8 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 Signed-off-by: Armin Kuster --- ...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 --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 -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 ---- - .../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 implements Schema { - 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 implements Schema { - 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 implements Schema { - 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 implements Schema { - 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 { - -+ 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 { - 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 { - 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 { - } - } - -- 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 { - 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 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 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 "