Copilot commented on code in PR #1060:
URL: https://github.com/apache/poi/pull/1060#discussion_r3213175639


##########
poi-scratchpad/src/test/java/org/apache/poi/hemf/usermodel/TestHemfPicture.java:
##########
@@ -229,6 +232,29 @@ void testInfiniteLoopOnByteArray() throws Exception {
         }
     }
 
+    @Test
+    void testHeaderDescriptionBoundsAreValidated() throws Exception {
+        HemfHeader header = new HemfHeader();
+        byte[] data = createHeaderRecordData(0x40000001L, 88);
+
+        try (LittleEndianInputStream leis = new LittleEndianInputStream(new 
ByteArrayInputStream(data))) {
+            assertThrows(RecordFormatException.class,
+                    () -> header.init(leis, data.length, 
HemfRecordType.header.id));
+        }
+    }
+
+    @Test
+    void testHeaderDescriptionParsesValidUtf16lePayload() throws Exception {
+        HemfHeader header = new HemfHeader();
+        byte[] data = createHeaderRecordDataWithDescription("POI");
+
+        try (LittleEndianInputStream leis = new LittleEndianInputStream(new 
ByteArrayInputStream(data))) {
+            long readSize = header.init(leis, data.length, 
HemfRecordType.header.id);
+            assertEquals(data.length, readSize);

Review Comment:
   `HemfHeader.init(...)` intentionally uses `mark()/reset()` to *peek* at the 
description without consuming it, so it typically returns the size of the fixed 
header fields (not the full buffer length when a description is present). As 
written, `assertEquals(data.length, readSize)` will fail once a description is 
appended. Either remove this assertion, or assert the expected consumed size 
(and/or explicitly skip the remaining bytes if you want to validate full 
consumption).
   



##########
poi-scratchpad/src/main/java/org/apache/poi/hemf/record/emf/HemfHeader.java:
##########
@@ -165,10 +167,17 @@ public long init(LittleEndianInputStream leis, long 
recordSize, long recordId) t
         size += readDimensionInt(leis, milliDimension);
 
         if (nDescription > 0 && offDescription > 0) {
-            int skip = (int)(offDescription - (size + HEADER_SIZE));
-            leis.mark(skip+nDescription*2);
-            leis.skipFully(skip);
-            byte[] buf = new byte[(nDescription-1)*2];
+            long skip = offDescription - (size + HEADER_SIZE);
+            long descriptionBytes = (nDescription - 1) * 
LittleEndianConsts.SHORT_SIZE;
+            long descriptionEnd = offDescription + nDescription * 
LittleEndianConsts.SHORT_SIZE;
+            if (skip < 0 || descriptionEnd > recordSize + HEADER_SIZE || skip 
+ descriptionBytes > Integer.MAX_VALUE) {
+                throw new RecordFormatException("Invalid EMF header 
description bounds");
+            }
+            int maxDescriptionLength = (int)Math.min(recordSize, 
Integer.MAX_VALUE);
+            IOUtils.safelyAllocateCheck(descriptionBytes, 
maxDescriptionLength);
+            leis.mark((int)(skip + descriptionBytes));
+            leis.skipFully((int)skip);
+            byte[] buf = IOUtils.safelyAllocate(descriptionBytes, 
maxDescriptionLength);

Review Comment:
   `maxDescriptionLength` is set to `recordSize` (capped at 
`Integer.MAX_VALUE`), which means `safelyAllocate*/check` won’t meaningfully 
limit allocation size when `recordSize` comes from a crafted EMF record header. 
This still allows multi-GB allocations (up to ~2GB) and potential OOM/DoS even 
though bounds are validated against the record’s declared size. Consider using 
a fixed, record-type-specific maximum (similar to `HemfText`’s max record 
length) or another established POI limit instead of `recordSize` here, so 
maliciously large declared record sizes can’t drive huge allocations.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to