This is an automated email from the ASF dual-hosted git repository.
pjfanning pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/poi.git
The following commit(s) were added to refs/heads/trunk by this push:
new d290db190b Apply allocation bounds checks to EMF+ path and brush
element counts (#1104)
d290db190b is described below
commit d290db190bb301bc717f5f568c65f57a3e3ee940
Author: jmestwa-coder <[email protected]>
AuthorDate: Wed Jun 3 19:21:32 2026 +0530
Apply allocation bounds checks to EMF+ path and brush element counts (#1104)
---
.../poi/hemf/record/emfplus/HemfPlusBrush.java | 4 ++
.../poi/hemf/record/emfplus/HemfPlusPath.java | 3 ++
.../poi/hemf/record/emfplus/TestHemfPlusBrush.java | 55 ++++++++++++++++++++++
.../poi/hemf/record/emfplus/TestHemfPlusPath.java | 26 ++++++++++
4 files changed, 88 insertions(+)
diff --git
a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusBrush.java
b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusBrush.java
index 337a77b9de..7237ec4443 100644
---
a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusBrush.java
+++
b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusBrush.java
@@ -53,6 +53,7 @@ import
org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectType;
import org.apache.poi.hemf.record.emfplus.HemfPlusPath.EmfPlusPath;
import org.apache.poi.hwmf.record.HwmfBrushStyle;
import org.apache.poi.hwmf.record.HwmfColorRef;
+import org.apache.poi.hwmf.usermodel.HwmfPicture;
import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
@@ -735,6 +736,7 @@ public class HemfPlusBrush {
// An array of SurroundingColorCount EmfPlusARGB objects that
specify the colors for discrete points on the
// boundary of the brush.
+ IOUtils.safelyAllocateCheck(colorCount,
HwmfPicture.getMaxRecordLength());
surroundingColor = new Color[colorCount];
for (int i = 0; i < colorCount; i++) {
surroundingColor[i] = readARGB(leis.readInt());
@@ -757,6 +759,7 @@ public class HemfPlusBrush {
size += LittleEndianConsts.INT_SIZE;
// An array of BoundaryPointCount EmfPlusPointF objects that
specify the boundary of the brush.
+ IOUtils.safelyAllocateCheck(pointCount,
HwmfPicture.getMaxRecordLength());
boundaryPoints = new Point2D[pointCount];
for (int i=0; i<pointCount; i++) {
size += readPointF(leis, boundaryPoints[i] = new
Point2D.Double());
@@ -912,6 +915,7 @@ public class HemfPlusBrush {
final int count = leis.readInt();
int size = LittleEndianConsts.INT_SIZE;
+ IOUtils.safelyAllocateCheck(count, HwmfPicture.getMaxRecordLength());
float[] positions = new float[count];
for (int i=0; i<count; i++) {
positions[i] = leis.readFloat();
diff --git
a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusPath.java
b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusPath.java
index 210e3a5063..cef5968044 100644
---
a/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusPath.java
+++
b/poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emfplus/HemfPlusPath.java
@@ -38,9 +38,11 @@ import
org.apache.poi.hemf.record.emfplus.HemfPlusDraw.EmfPlusRelativePosition;
import
org.apache.poi.hemf.record.emfplus.HemfPlusHeader.EmfPlusGraphicsVersion;
import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectData;
import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectType;
+import org.apache.poi.hwmf.usermodel.HwmfPicture;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordUtil;
+import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@@ -119,6 +121,7 @@ public class HemfPlusPath {
readPoint = HemfPlusDraw::readPointF;
}
+ IOUtils.safelyAllocateCheck(pointCount,
HwmfPicture.getMaxRecordLength());
pathPoints = new Point2D[pointCount];
for (int i=0; i<pointCount; i++) {
pathPoints[i] = new Point2D.Double();
diff --git
a/poi-scratchpad/src/test/java/org/apache/poi/hemf/record/emfplus/TestHemfPlusBrush.java
b/poi-scratchpad/src/test/java/org/apache/poi/hemf/record/emfplus/TestHemfPlusBrush.java
new file mode 100644
index 0000000000..79bc4b5dbe
--- /dev/null
+++
b/poi-scratchpad/src/test/java/org/apache/poi/hemf/record/emfplus/TestHemfPlusBrush.java
@@ -0,0 +1,55 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hemf.record.emfplus;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.ByteArrayInputStream;
+
+import
org.apache.poi.hemf.record.emfplus.HemfPlusBrush.EmfPlusPathGradientBrushData;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInputStream;
+import org.apache.poi.util.RecordFormatException;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+class TestHemfPlusBrush {
+
+ /**
+ * EmfPlusPathGradientBrushData reads a 32-bit surrounding-color count
straight
+ * from the EMF+ stream and allocates the color array before any color
data is
+ * read. A crafted count (oversized or negative) must be rejected by the
+ * standard allocation check instead of triggering an OutOfMemoryError /
+ * NegativeArraySizeException.
+ */
+ @ParameterizedTest
+ @ValueSource(ints = { Integer.MAX_VALUE, 0xFFFFFFFF })
+ void rejectsInvalidSurroundingColorCount(int colorCount) throws Exception {
+ byte[] data = new byte[24];
+ LittleEndian.putInt(data, 0, 0); // dataFlags
+ LittleEndian.putInt(data, 4, 0); // wrapMode ->
WRAP_MODE_TILE
+ LittleEndian.putInt(data, 8, 0); // centerColor
+ // bytes 12..19: centerPoint (two floats)
+ LittleEndian.putInt(data, 20, colorCount); // surrounding color count
+
+ EmfPlusPathGradientBrushData brush = new
EmfPlusPathGradientBrushData();
+ try (LittleEndianInputStream leis = new LittleEndianInputStream(new
ByteArrayInputStream(data))) {
+ assertThrows(RecordFormatException.class, () -> brush.init(leis,
data.length));
+ }
+ }
+}
diff --git
a/poi-scratchpad/src/test/java/org/apache/poi/hemf/record/emfplus/TestHemfPlusPath.java
b/poi-scratchpad/src/test/java/org/apache/poi/hemf/record/emfplus/TestHemfPlusPath.java
index 26792374c4..02706f5d3c 100644
---
a/poi-scratchpad/src/test/java/org/apache/poi/hemf/record/emfplus/TestHemfPlusPath.java
+++
b/poi-scratchpad/src/test/java/org/apache/poi/hemf/record/emfplus/TestHemfPlusPath.java
@@ -18,6 +18,7 @@
package org.apache.poi.hemf.record.emfplus;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.ByteArrayInputStream;
@@ -25,7 +26,10 @@ import
org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectType;
import org.apache.poi.hemf.record.emfplus.HemfPlusPath.EmfPlusPath;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianInputStream;
+import org.apache.poi.util.RecordFormatException;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
class TestHemfPlusPath {
@@ -57,4 +61,26 @@ class TestHemfPlusPath {
assertDoesNotThrow(() -> path.init(leis, data.length,
EmfPlusObjectType.PATH, 0));
}
}
+
+ /**
+ * EmfPlusPath reads a 32-bit point count straight from the EMF+ stream and
+ * allocates the point/type arrays before any point data is read. A crafted
+ * count (oversized or negative) must be rejected by the standard
allocation
+ * check instead of triggering an OutOfMemoryError /
NegativeArraySizeException.
+ */
+ @ParameterizedTest
+ @ValueSource(ints = { Integer.MAX_VALUE, 0xFFFFFFFF })
+ void rejectsInvalidPointCount(int pointCount) throws Exception {
+ byte[] data = new byte[12];
+ // EmfPlusGraphicsVersion: metafile signature 0xDBC01, graphics
version 1
+ LittleEndian.putInt(data, 0, 0xDBC01001);
+ LittleEndian.putInt(data, 4, pointCount);
+ // remaining 4 bytes: pointFlags (2) + reserved (2)
+
+ EmfPlusPath path = new EmfPlusPath();
+ try (LittleEndianInputStream leis = new LittleEndianInputStream(new
ByteArrayInputStream(data))) {
+ assertThrows(RecordFormatException.class,
+ () -> path.init(leis, data.length, EmfPlusObjectType.PATH,
0));
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]