From 6d0ab1ef3ad6d56f23dfecb98607c973e5a40e31 Mon Sep 17 00:00:00 2001 From: digi-scrypt Date: Fri, 5 Jun 2026 20:38:01 +0530 Subject: [PATCH 1/3] validate deserialized size in CircularFifoQueue.readObject --- .../collections4/queue/CircularFifoQueue.java | 7 +++ .../queue/CircularFifoQueueTest.java | 51 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/main/java/org/apache/commons/collections4/queue/CircularFifoQueue.java b/src/main/java/org/apache/commons/collections4/queue/CircularFifoQueue.java index 3988666e7d..9417583e34 100644 --- a/src/main/java/org/apache/commons/collections4/queue/CircularFifoQueue.java +++ b/src/main/java/org/apache/commons/collections4/queue/CircularFifoQueue.java @@ -17,6 +17,7 @@ package org.apache.commons.collections4.queue; import java.io.IOException; +import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; @@ -358,8 +359,14 @@ public E poll() { @SuppressWarnings("unchecked") private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + if (maxElements < 1) { + throw new InvalidObjectException("maxElements must be greater than 0"); + } elements = (E[]) new Object[maxElements]; final int size = in.readInt(); + if (size < 0 || size > maxElements) { + throw new InvalidObjectException("size is out of range: " + size); + } for (int i = 0; i < size; i++) { elements[i] = (E) in.readObject(); } diff --git a/src/test/java/org/apache/commons/collections4/queue/CircularFifoQueueTest.java b/src/test/java/org/apache/commons/collections4/queue/CircularFifoQueueTest.java index 35340d6e27..01654bfdc2 100644 --- a/src/test/java/org/apache/commons/collections4/queue/CircularFifoQueueTest.java +++ b/src/test/java/org/apache/commons/collections4/queue/CircularFifoQueueTest.java @@ -23,6 +23,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; @@ -444,6 +445,56 @@ void testRepeatedSerialization() throws Exception { assertTrue(b3.contains("c")); } + @Test + @SuppressWarnings("unchecked") + void testDeserializeRejectsCorruptSize() throws Exception { + // a stored size larger than maxElements would write past the backing array + final CircularFifoQueue full = new CircularFifoQueue<>(7); + for (int i = 0; i < 7; i++) { + full.add((E) ("x" + i)); + } + final byte[] tooLarge = serialize(full); + // first 0x00000007 is maxElements; shrink it so size (7) now exceeds it + patchInt(tooLarge, indexOfInt(tooLarge, 7), 2); + assertThrows(InvalidObjectException.class, () -> deserialize(tooLarge)); + + // a negative stored size leaves the queue in an inconsistent state + final CircularFifoQueue partial = new CircularFifoQueue<>(7); + partial.add((E) "a"); + partial.add((E) "b"); + final byte[] negative = serialize(partial); + patchInt(negative, indexOfInt(negative, 2), -1); + assertThrows(InvalidObjectException.class, () -> deserialize(negative)); + } + + private static byte[] serialize(final Object obj) throws Exception { + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + new ObjectOutputStream(bos).writeObject(obj); + return bos.toByteArray(); + } + + private static Object deserialize(final byte[] data) throws Exception { + return new ObjectInputStream(new ByteArrayInputStream(data)).readObject(); + } + + private static int indexOfInt(final byte[] data, final int value) { + final byte[] needle = {(byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value}; + for (int i = 0; i <= data.length - 4; i++) { + if (data[i] == needle[0] && data[i + 1] == needle[1] + && data[i + 2] == needle[2] && data[i + 3] == needle[3]) { + return i; + } + } + throw new IllegalStateException("value not found in stream"); + } + + private static void patchInt(final byte[] data, final int pos, final int value) { + data[pos] = (byte) (value >>> 24); + data[pos + 1] = (byte) (value >>> 16); + data[pos + 2] = (byte) (value >>> 8); + data[pos + 3] = (byte) value; + } + // void testCreate() throws Exception { // resetEmpty(); // writeExternalFormToDisk((java.io.Serializable) getCollection(), "src/test/resources/data/test/CircularFifoQueue.emptyCollection.version4.obj"); From c7630f6aee2dfd674dbdf64379823dda3fd65354 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sat, 27 Jun 2026 14:36:54 -0400 Subject: [PATCH 2/3] Update CircularFifoQueueTest.java --- .../collections4/queue/CircularFifoQueueTest.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/test/java/org/apache/commons/collections4/queue/CircularFifoQueueTest.java b/src/test/java/org/apache/commons/collections4/queue/CircularFifoQueueTest.java index 994c3ddb2b..ed6fb1ee36 100644 --- a/src/test/java/org/apache/commons/collections4/queue/CircularFifoQueueTest.java +++ b/src/test/java/org/apache/commons/collections4/queue/CircularFifoQueueTest.java @@ -455,16 +455,6 @@ void testDeserializeRejectsCorruptSize() throws Exception { assertThrows(InvalidObjectException.class, () -> deserialize(negative)); } - private static byte[] serialize(final Object obj) throws Exception { - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - new ObjectOutputStream(bos).writeObject(obj); - return bos.toByteArray(); - } - - private static Object deserialize(final byte[] data) throws Exception { - return new ObjectInputStream(new ByteArrayInputStream(data)).readObject(); - } - private static int indexOfInt(final byte[] data, final int value) { final byte[] needle = {(byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value}; for (int i = 0; i <= data.length - 4; i++) { From aee65a2fd69b504370133e56e451662fd8818cb6 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sat, 27 Jun 2026 14:42:17 -0400 Subject: [PATCH 3/3] Update CircularFifoQueueTest.java --- .../commons/collections4/queue/CircularFifoQueueTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/test/java/org/apache/commons/collections4/queue/CircularFifoQueueTest.java b/src/test/java/org/apache/commons/collections4/queue/CircularFifoQueueTest.java index ed6fb1ee36..20df0a8acf 100644 --- a/src/test/java/org/apache/commons/collections4/queue/CircularFifoQueueTest.java +++ b/src/test/java/org/apache/commons/collections4/queue/CircularFifoQueueTest.java @@ -21,11 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.InvalidObjectException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection;