From: Tim Allison Date: Wed, 26 Jul 2017 12:46:24 +0000 (+0000) Subject: 61346 add more sanity checks before allocating byte arrays in emf/wmf X-Git-Tag: REL_3_17_FINAL~34 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=a9c40720714e54bace78e9dc4e923f4af59f1a78;p=poi.git 61346 add more sanity checks before allocating byte arrays in emf/wmf git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1803041 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/util/IOUtils.java b/src/java/org/apache/poi/util/IOUtils.java index 25e5652d93..b256591fa0 100644 --- a/src/java/org/apache/poi/util/IOUtils.java +++ b/src/java/org/apache/poi/util/IOUtils.java @@ -431,4 +431,19 @@ public final class IOUtils { return toSkip - remain; } + public static byte[] safelyAllocate(long length, int maxLength) { + if (length < 0L) { + throw new RecordFormatException("Can't allocate an array of length < 0"); + } + if (length > (long)Integer.MAX_VALUE) { + throw new RecordFormatException("Can't allocate an array > "+Integer.MAX_VALUE); + } + if (length > maxLength) { + throw new RecordFormatException("Not allowed to allocate an array > "+ + maxLength+" for this record type." + + "If the file is not corrupt, please open an issue on bugzilla to request " + + "increasing the maximum allowable size for this record type"); + } + return new byte[(int)length]; + } } diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentEMFPlus.java b/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentEMFPlus.java index b32bf5481d..1129839649 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentEMFPlus.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentEMFPlus.java @@ -23,6 +23,7 @@ import java.util.List; import org.apache.poi.hemf.hemfplus.record.HemfPlusRecord; import org.apache.poi.hemf.hemfplus.record.HemfPlusRecordType; +import org.apache.poi.util.IOUtils; import org.apache.poi.util.Internal; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.RecordFormatException; @@ -33,6 +34,9 @@ import org.apache.poi.util.RecordFormatException; @Internal public class HemfCommentEMFPlus extends AbstractHemfComment { + private static final int MAX_RECORD_LENGTH = 1000000; + + long dataSize; public HemfCommentEMFPlus(byte[] rawBytes) { //these rawBytes contain only the EMFPlusRecord(s?) @@ -93,7 +97,7 @@ public class HemfCommentEMFPlus extends AbstractHemfComment { } catch (IllegalAccessException e) { throw new RuntimeException(e); } - byte[] dataBytes = new byte[size]; + byte[] dataBytes = IOUtils.safelyAllocate(size, MAX_RECORD_LENGTH); System.arraycopy(bytes, offset, dataBytes, 0, size); try { record.init(dataBytes, recordId, flags); diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentPublic.java b/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentPublic.java index 87f282d653..7674443839 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentPublic.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentPublic.java @@ -23,6 +23,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import org.apache.poi.util.IOUtils; import org.apache.poi.util.Internal; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndianConsts; @@ -35,6 +36,9 @@ import org.apache.poi.util.RecordFormatException; @Internal public class HemfCommentPublic { + private static final int MAX_RECORD_LENGTH = 1000000; + + /** * Stub, to be implemented */ @@ -80,7 +84,7 @@ public class HemfCommentPublic { } List list = new ArrayList(); for (EmrFormat emrFormat : emrFormatList) { - byte[] data = new byte[emrFormat.size]; + byte[] data = IOUtils.safelyAllocate(emrFormat.size, MAX_RECORD_LENGTH); System.arraycopy(rawBytes, emrFormat.offset-4, data, 0, emrFormat.size); list.add(new HemfMultiFormatsData(emrFormat.signature, emrFormat.version, data)); } @@ -129,12 +133,8 @@ public class HemfCommentPublic { wmfBytes = new byte[0]; return; } - if (winMetafileSizeLong > Integer.MAX_VALUE) { - throw new RecordFormatException("Metafile record length can't be > Integer.MAX_VALUE"); - } - int winMetafileSize = (int)winMetafileSizeLong; - wmfBytes = new byte[winMetafileSize]; - System.arraycopy(rawBytes, offset, wmfBytes, 0, winMetafileSize); + wmfBytes = IOUtils.safelyAllocate(winMetafileSizeLong, MAX_RECORD_LENGTH); + System.arraycopy(rawBytes, offset, wmfBytes, 0, wmfBytes.length); } /** diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentRecord.java b/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentRecord.java index 2e8c17d7ad..90510f8d8f 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentRecord.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentRecord.java @@ -36,6 +36,7 @@ import org.apache.poi.util.RecordFormatException; */ @Internal public class HemfCommentRecord implements HemfRecord { + private static final int MAX_RECORD_LENGTH = 1000000; public final static long COMMENT_EMFSPOOL = 0x00000000; public final static long COMMENT_EMFPLUS = 0x2B464D45; @@ -87,7 +88,7 @@ public class HemfCommentRecord implements HemfRecord { int dataSize = (int)remainingDataSize; int recordSize = (int)remainingRecordSize; - byte[] arr = new byte[dataSize+initialBytes.length]; + byte[] arr = IOUtils.safelyAllocate(dataSize+initialBytes.length, MAX_RECORD_LENGTH); System.arraycopy(initialBytes,0,arr, 0, initialBytes.length); long read = IOUtils.readFully(leis, arr, initialBytes.length, dataSize); if (read != dataSize) { @@ -103,13 +104,12 @@ public class HemfCommentRecord implements HemfRecord { } private byte[] readToByteArray(LittleEndianInputStream leis, long dataSize, long recordSize) throws IOException { - assert dataSize < Integer.MAX_VALUE; if (recordSize == 0) { return new byte[0]; } - byte[] arr = new byte[(int)dataSize]; + byte[] arr = IOUtils.safelyAllocate(dataSize, MAX_RECORD_LENGTH); long read = IOUtils.readFully(leis, arr); if (read != dataSize) { diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/HemfHeader.java b/src/scratchpad/src/org/apache/poi/hemf/record/HemfHeader.java index a23f4fdae2..2c3694c844 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/HemfHeader.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/HemfHeader.java @@ -32,6 +32,9 @@ import org.apache.poi.util.LittleEndianInputStream; @Internal public class HemfHeader implements HemfRecord { + private static final int MAX_RECORD_LENGTH = 1000000; + + private Rectangle boundsRectangle; private Rectangle frameRectangle; private long bytes; @@ -140,7 +143,7 @@ public class HemfHeader implements HemfRecord { throw new IOException("Not a valid EMF header. Record type:"+recordId); } //read the record--id and size (2 bytes) have already been read - byte[] data = new byte[(int)recordSize]; + byte[] data = IOUtils.safelyAllocate(recordSize, MAX_RECORD_LENGTH); IOUtils.readFully(leis, data); int offset = 0; diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/HemfText.java b/src/scratchpad/src/org/apache/poi/hemf/record/HemfText.java index c40e493bdb..8c32812d7f 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/HemfText.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/HemfText.java @@ -39,7 +39,8 @@ import org.apache.poi.util.RecordFormatException; @Internal public class HemfText { - private final static Charset UTF16LE = Charset.forName("UTF-16LE"); + private static final Charset UTF16LE = Charset.forName("UTF-16LE"); + private static final int MAX_RECORD_LENGTH = 1000000; public static class ExtCreateFontIndirectW extends UnimplementedHemfRecord { } @@ -80,7 +81,7 @@ public class HemfText { } //guarantee to read the rest of the EMRTextObjectRecord //emrtextbytes start after 7*4 bytes read above - byte[] emrTextBytes = new byte[recordSizeInt-(7*LittleEndian.INT_SIZE)]; + byte[] emrTextBytes = IOUtils.safelyAllocate(recordSizeInt-(7*LittleEndian.INT_SIZE), MAX_RECORD_LENGTH); IOUtils.readFully(leis, emrTextBytes); textObject = new EmrTextObject(emrTextBytes, getEncodingHint(), 20);//should be 28, but recordSizeInt has already subtracted 8 return recordSize; @@ -218,9 +219,12 @@ public class HemfText { } if (numCharsLong > Integer.MAX_VALUE) { throw new RecordFormatException("Number of characters can't be > Integer.MAX_VALUE"); + } else if (numCharsLong < 0) { + throw new RecordFormatException("Number of characters can't be < 0"); } + numChars = (int)numCharsLong; - rawTextBytes = new byte[emrTextObjBytes.length-start]; + rawTextBytes = IOUtils.safelyAllocate(emrTextObjBytes.length-start, MAX_RECORD_LENGTH); System.arraycopy(emrTextObjBytes, start, rawTextBytes, 0, emrTextObjBytes.length-start); } diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java index ce4d148796..b9522730e6 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java @@ -17,6 +17,7 @@ package org.apache.poi.hwmf.record; +import javax.imageio.ImageIO; import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; @@ -24,8 +25,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import javax.imageio.ImageIO; - import org.apache.poi.util.IOUtils; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndianConsts; @@ -38,6 +37,9 @@ import org.apache.poi.util.RecordFormatException; * The DeviceIndependentBitmap Object defines an image in device-independent bitmap (DIB) format. */ public class HwmfBitmapDib { + + private static final int MAX_RECORD_LENGTH = 10000000; + public static enum BitCount { /** * The image SHOULD be in either JPEG or PNG format. <6> Neither of these formats includes @@ -385,7 +387,7 @@ public class HwmfBitmapDib { int imageSize = (int)Math.max(imageData.length, introSize+headerImageSize); // create the image data and leave the parsing to the ImageIO api - byte buf[] = new byte[BMP_HEADER_SIZE+imageSize]; + byte buf[] = IOUtils.safelyAllocate(BMP_HEADER_SIZE+imageSize, MAX_RECORD_LENGTH); // https://en.wikipedia.org/wiki/BMP_file_format # Bitmap file header buf[0] = (byte)'B'; diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java index 9bcac30d06..928b31128d 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java @@ -26,6 +26,7 @@ import org.apache.poi.hwmf.draw.HwmfGraphics; import org.apache.poi.hwmf.record.HwmfMisc.WmfSetMapMode; import org.apache.poi.util.BitField; import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.IOUtils; import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianInputStream; import org.apache.poi.util.POILogFactory; @@ -33,7 +34,8 @@ import org.apache.poi.util.POILogger; public class HwmfText { private static final POILogger logger = POILogFactory.getLogger(HwmfText.class); - + private static final int MAX_RECORD_LENGTH = 1000000; + /** * The META_SETTEXTCHAREXTRA record defines inter-character spacing for text justification in the * playback device context. Spacing is added to the white space between each character, including @@ -164,7 +166,7 @@ public class HwmfText { @Override public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { stringLength = leis.readShort(); - rawTextBytes = new byte[stringLength+(stringLength&1)]; + rawTextBytes = IOUtils.safelyAllocate(stringLength+(stringLength&1), MAX_RECORD_LENGTH); leis.readFully(rawTextBytes); yStart = leis.readShort(); xStart = leis.readShort(); @@ -188,7 +190,7 @@ public class HwmfText { * This does not include the extra optional padding on the byte array. */ private byte[] getTextBytes() { - byte[] ret = new byte[stringLength]; + byte[] ret = IOUtils.safelyAllocate(stringLength, MAX_RECORD_LENGTH); System.arraycopy(rawTextBytes, 0, ret, 0, stringLength); return ret; } @@ -315,7 +317,7 @@ public class HwmfText { size += 4*LittleEndianConsts.SHORT_SIZE; } - rawTextBytes = new byte[stringLength+(stringLength&1)]; + rawTextBytes = IOUtils.safelyAllocate(stringLength+(stringLength&1), MAX_RECORD_LENGTH); leis.readFully(rawTextBytes); size += rawTextBytes.length; @@ -355,7 +357,7 @@ public class HwmfText { * This does not include the extra optional padding on the byte array. */ private byte[] getTextBytes() { - byte[] ret = new byte[stringLength]; + byte[] ret = IOUtils.safelyAllocate(stringLength, MAX_RECORD_LENGTH); System.arraycopy(rawTextBytes, 0, ret, 0, stringLength); return ret; }