7058700: Unexpected exceptions and timeouts in SF2 parser code
Reviewed-by: prr, pchelko
--- a/jdk/src/share/classes/com/sun/media/sound/RIFFReader.java Thu Jul 31 23:00:24 2014 +0400
+++ b/jdk/src/share/classes/com/sun/media/sound/RIFFReader.java Thu Jul 31 21:09:52 2014 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,21 +39,20 @@
private long filepointer = 0;
private final String fourcc;
private String riff_type = null;
- private long ckSize = 0;
+ private long ckSize = Integer.MAX_VALUE;
private InputStream stream;
- private long avail;
+ private long avail = Integer.MAX_VALUE;
private RIFFReader lastiterator = null;
public RIFFReader(InputStream stream) throws IOException {
- if (stream instanceof RIFFReader)
- root = ((RIFFReader)stream).root;
- else
+ if (stream instanceof RIFFReader) {
+ root = ((RIFFReader) stream).root;
+ } else {
root = this;
+ }
this.stream = stream;
- avail = Integer.MAX_VALUE;
- ckSize = Integer.MAX_VALUE;
// Check for RIFF null paddings,
int b;
@@ -75,9 +74,12 @@
fourcc[0] = (byte) b;
readFully(fourcc, 1, 3);
this.fourcc = new String(fourcc, "ascii");
- ckSize = readUnsignedInt();
-
- avail = this.ckSize;
+ final long size = readUnsignedInt();
+ if (size > Integer.MAX_VALUE) {
+ throw new RIFFInvalidDataException("Chunk size too big");
+ }
+ ckSize = size;
+ avail = size;
if (getFormat().equals("RIFF") || getFormat().equals("LIST")) {
byte[] format = new byte[4];
@@ -118,19 +120,23 @@
}
public int read() throws IOException {
- if (avail == 0)
+ if (avail == 0) {
return -1;
+ }
int b = stream.read();
- if (b == -1)
+ if (b == -1) {
+ avail = 0;
return -1;
+ }
avail--;
filepointer++;
return b;
}
public int read(byte[] b, int offset, int len) throws IOException {
- if (avail == 0)
+ if (avail == 0) {
return -1;
+ }
if (len > avail) {
int rlen = stream.read(b, offset, (int)avail);
if (rlen != -1)
@@ -139,8 +145,10 @@
return rlen;
} else {
int ret = stream.read(b, offset, len);
- if (ret == -1)
+ if (ret == -1) {
+ avail = 0;
return -1;
+ }
avail -= ret;
filepointer += ret;
return ret;
@@ -191,8 +199,10 @@
return len;
} else {
long ret = stream.skip(n);
- if (ret == -1)
+ if (ret == -1) {
+ avail = 0;
return -1;
+ }
avail -= ret;
filepointer += ret;
return ret;
@@ -210,8 +220,13 @@
}
// Read ASCII chars from stream
- public String readString(int len) throws IOException {
- byte[] buff = new byte[len];
+ public String readString(final int len) throws IOException {
+ final byte[] buff;
+ try {
+ buff = new byte[len];
+ } catch (final OutOfMemoryError oom) {
+ throw new IOException("Length too big", oom);
+ }
readFully(buff);
for (int i = 0; i < buff.length; i++) {
if (buff[i] == 0) {
--- a/jdk/src/share/classes/com/sun/media/sound/SF2Soundbank.java Thu Jul 31 23:00:24 2014 +0400
+++ b/jdk/src/share/classes/com/sun/media/sound/SF2Soundbank.java Thu Jul 31 21:09:52 2014 +0100
@@ -276,6 +276,9 @@
count--;
}
+ if (presets_bagNdx.isEmpty()) {
+ throw new RIFFInvalidDataException();
+ }
int offset = presets_bagNdx.get(0);
// Offset should be 0 (but just case)
for (int i = 0; i < offset; i++) {
@@ -360,6 +363,9 @@
count--;
}
+ if (instruments_bagNdx.isEmpty()) {
+ throw new RIFFInvalidDataException();
+ }
int offset = instruments_bagNdx.get(0);
// Offset should be 0 (but just case)
for (int i = 0; i < offset; i++) {
@@ -401,6 +407,9 @@
modulator.amount = chunk.readShort();
modulator.amountSourceOperator = chunk.readUnsignedShort();
modulator.transportOperator = chunk.readUnsignedShort();
+ if (i < 0 || i >= instruments_splits_gen.size()) {
+ throw new RIFFInvalidDataException();
+ }
SF2LayerRegion split = instruments_splits_gen.get(i);
if (split != null)
split.modulators.add(modulator);
@@ -424,7 +433,8 @@
sample.name = chunk.readString(20);
long start = chunk.readUnsignedInt();
long end = chunk.readUnsignedInt();
- sample.data = sampleData.subbuffer(start * 2, end * 2, true);
+ if (sampleData != null)
+ sample.data = sampleData.subbuffer(start * 2, end * 2, true);
if (sampleData24 != null)
sample.data24 = sampleData24.subbuffer(start, end, true);
/*
@@ -462,6 +472,9 @@
int sampleid = split.generators.get(
SF2LayerRegion.GENERATOR_SAMPLEID);
split.generators.remove(SF2LayerRegion.GENERATOR_SAMPLEID);
+ if (sampleid < 0 || sampleid >= samples.size()) {
+ throw new RIFFInvalidDataException();
+ }
split.sample = samples.get(sampleid);
} else {
globalsplit = split;
@@ -488,6 +501,9 @@
int instrumentid = split.generators.get(
SF2InstrumentRegion.GENERATOR_INSTRUMENT);
split.generators.remove(SF2LayerRegion.GENERATOR_INSTRUMENT);
+ if (instrumentid < 0 || instrumentid >= layers.size()) {
+ throw new RIFFInvalidDataException();
+ }
split.layer = layers.get(instrumentid);
} else {
globalsplit = split;