summaryrefslogtreecommitdiff
path: root/java/src/IceInternal/BasicStream.java
diff options
context:
space:
mode:
authorMichi Henning <michi@zeroc.com>2004-05-10 02:48:56 +0000
committerMichi Henning <michi@zeroc.com>2004-05-10 02:48:56 +0000
commit3dfce9518b0e65a824c8812fbc4002b46ebea01b (patch)
tree52607ae520395e093b17ff2a3d5eebe8228d73f3 /java/src/IceInternal/BasicStream.java
parentMerged changes from michi_pre_e3 branch (diff)
downloadice-3dfce9518b0e65a824c8812fbc4002b46ebea01b.tar.bz2
ice-3dfce9518b0e65a824c8812fbc4002b46ebea01b.tar.xz
ice-3dfce9518b0e65a824c8812fbc4002b46ebea01b.zip
merging changes from branch michi_pre_e3
Diffstat (limited to 'java/src/IceInternal/BasicStream.java')
-rw-r--r--java/src/IceInternal/BasicStream.java175
1 files changed, 170 insertions, 5 deletions
diff --git a/java/src/IceInternal/BasicStream.java b/java/src/IceInternal/BasicStream.java
index ede70265d55..126be6eeba6 100644
--- a/java/src/IceInternal/BasicStream.java
+++ b/java/src/IceInternal/BasicStream.java
@@ -38,6 +38,7 @@ public class BasicStream
_messageSizeMax = _instance.messageSizeMax(); // Cached for efficiency.
+ _seqDataStack = null;
_objectList = null;
}
@@ -125,6 +126,10 @@ public class BasicStream
other._writeSlice = _writeSlice;
_writeSlice = tmpWriteSlice;
+ SeqData tmpSeqDataStack = other._seqDataStack;
+ other._seqDataStack = _seqDataStack;
+ _seqDataStack = tmpSeqDataStack;
+
java.util.ArrayList tmpObjectList = other._objectList;
other._objectList = _objectList;
_objectList = tmpObjectList;
@@ -179,6 +184,138 @@ public class BasicStream
return _buf;
}
+ //
+ // startSeq() and endSeq() sanity-check sequence sizes during
+ // unmarshaling and prevent malicious messages with incorrect
+ // sequence sizes from causing the receiver to use up all
+ // available memory by allocating sequences with an impossibly
+ // large number of elements.
+ //
+ // The code generator inserts calls to startSeq() and endSeq()
+ // around the code to unmarshal a sequence. startSeq() is called
+ // immediately after reading the sequence size, and endSeq() is
+ // called after reading the final element of a sequence.
+ //
+ // For sequences that contain constructed types that, in turn,
+ // contain sequences, the code generator also inserts a call
+ // to endElement() after unmarshaling each element.
+ //
+ // startSeq() is passed the unmarshaled element count, plus
+ // the minimum size (in bytes) occupied by the sequence's
+ // element type. numElements * minSize is the smallest
+ // possible number of bytes that the sequence will occupy
+ // on the wire.
+ //
+ // Every time startSeq() is called, it pushes the element
+ // count and the minimum size on a stack. Every time endSeq()
+ // is called, it pops the stack.
+ //
+ // For an ordinary sequence (one that does not (recursively)
+ // contain nested sequences), numElements * minSize must be
+ // less than the number of bytes remaining in the stream.
+ //
+ // For a sequence that is nested within some other sequence,
+ // there must be enough bytes remaining in the stream for
+ // this sequence (numElements + minSize), plus the sum of
+ // the bytes required by the remaining elements of all
+ // the enclosing sequences.
+ //
+ // For the enclosing sequences, numElements - 1 is the
+ // number of elements for which unmarshaling has not started
+ // yet. (The call to endElement() in the generated code
+ // decrements that number whenever a sequence element is
+ // unmarshaled.)
+ //
+ // For sequence that variable-length elements, checkSeq() is called
+ // whenever an element is unmarshaled. checkSeq() also checks
+ // whether the stream has a sufficient number of bytes remaining.
+ // This means that, for messages with bogus sequence sizes,
+ // unmarshaling is aborted at the earliest possible point.
+ //
+
+ public void
+ startSeq(int numElements, int minSize)
+ {
+ if(numElements == 0) // Optimization to avoid pushing a useless stack frame.
+ {
+ return;
+ }
+
+ //
+ // Push the current sequence details on the stack.
+ //
+ SeqData sd = new SeqData(numElements, minSize);
+ sd.previous = _seqDataStack;
+ _seqDataStack = sd;
+
+ int bytesLeft = _buf.remaining();
+ if(_seqDataStack == null) // Outermost sequence
+ {
+ //
+ // The sequence must fit within the message.
+ //
+ if(numElements * minSize > bytesLeft)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ }
+ else // Nested sequence
+ {
+ checkSeq(bytesLeft);
+ }
+ }
+
+ //
+ // Check, given the number of elements requested for this sequence,
+ // that this sequence, plus the sum of the sizes of the remaining
+ // number of elements of all enclosing sequences, would still fit within the message.
+ //
+ public void
+ checkSeq()
+ {
+ checkSeq(_buf.remaining());
+ }
+
+ public void
+ checkSeq(int bytesLeft)
+ {
+ int size = 0;
+ SeqData sd = _seqDataStack;
+ do
+ {
+ size += (sd.numElements - 1) * sd.minSize;
+ sd = sd.previous;
+ }
+ while(sd != null);
+
+ if(size > bytesLeft)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ }
+
+ public void
+ endSeq(int sz)
+ {
+ if(sz == 0) // Pop only if something was pushed previously.
+ {
+ return;
+ }
+
+ //
+ // Pop the sequence stack.
+ //
+ SeqData oldSeqData = _seqDataStack;
+ assert(oldSeqData != null);
+ _seqDataStack = oldSeqData.previous;
+ }
+
+ public void endElement()
+ {
+ assert(_seqDataStack != null);
+ --_seqDataStack.numElements;
+ }
+
public void
startWriteEncaps()
{
@@ -268,7 +405,7 @@ public class BasicStream
/*
if(sz - 4 > _buf.length())
{
- throw UnmarshalOutOfBoundsException(__FILE__, __LINE__);
+ throw new Ice.UnmarshalOutOfBoundsException();
}
*/
_readEncapsStack.sz = sz;
@@ -539,8 +676,10 @@ public class BasicStream
try
{
final int sz = readSize();
+ startSeq(sz, 1);
byte[] v = new byte[sz];
_buf.get(v);
+ endSeq(sz);
return v;
}
catch(java.nio.BufferUnderflowException ex)
@@ -593,11 +732,13 @@ public class BasicStream
try
{
final int sz = readSize();
+ startSeq(sz, 1);
boolean[] v = new boolean[sz];
for(int i = 0; i < sz; i++)
{
v[i] = _buf.get() == 1;
}
+ endSeq(sz);
return v;
}
catch(java.nio.BufferUnderflowException ex)
@@ -649,10 +790,12 @@ public class BasicStream
try
{
final int sz = readSize();
+ startSeq(sz, 2);
short[] v = new short[sz];
java.nio.ShortBuffer shortBuf = _buf.asShortBuffer();
shortBuf.get(v);
_buf.position(_buf.position() + sz * 2);
+ endSeq(sz);
return v;
}
catch(java.nio.BufferUnderflowException ex)
@@ -704,10 +847,12 @@ public class BasicStream
try
{
final int sz = readSize();
+ startSeq(sz, 4);
int[] v = new int[sz];
java.nio.IntBuffer intBuf = _buf.asIntBuffer();
intBuf.get(v);
_buf.position(_buf.position() + sz * 4);
+ endSeq(sz);
return v;
}
catch(java.nio.BufferUnderflowException ex)
@@ -759,10 +904,12 @@ public class BasicStream
try
{
final int sz = readSize();
+ startSeq(sz, 8);
long[] v = new long[sz];
java.nio.LongBuffer longBuf = _buf.asLongBuffer();
longBuf.get(v);
_buf.position(_buf.position() + sz * 8);
+ endSeq(sz);
return v;
}
catch(java.nio.BufferUnderflowException ex)
@@ -814,10 +961,12 @@ public class BasicStream
try
{
final int sz = readSize();
+ startSeq(sz, 4);
float[] v = new float[sz];
java.nio.FloatBuffer floatBuf = _buf.asFloatBuffer();
floatBuf.get(v);
_buf.position(_buf.position() + sz * 4);
+ endSeq(sz);
return v;
}
catch(java.nio.BufferUnderflowException ex)
@@ -869,10 +1018,12 @@ public class BasicStream
try
{
final int sz = readSize();
+ startSeq(sz, 8);
double[] v = new double[sz];
java.nio.DoubleBuffer doubleBuf = _buf.asDoubleBuffer();
doubleBuf.get(v);
_buf.position(_buf.position() + sz * 8);
+ endSeq(sz);
return v;
}
catch(java.nio.BufferUnderflowException ex)
@@ -990,16 +1141,16 @@ public class BasicStream
public String[]
readStringSeq()
{
- //
- // TODO: This code is dangerous, because it cannot be
- // checked whether sz is a reasonable value.
- //
final int sz = readSize();
+ startSeq(sz, 1);
String[] v = new String[sz];
for(int i = 0; i < sz; i++)
{
v[i] = readString();
+ checkSeq();
+ endElement();
}
+ endSeq(sz);
return v;
}
@@ -1757,5 +1908,19 @@ public class BasicStream
private int _messageSizeMax;
+ private static final class SeqData
+ {
+ public SeqData(int numElements, int minSize)
+ {
+ this.numElements = numElements;
+ this.minSize = minSize;
+ }
+
+ public int numElements;
+ public int minSize;
+ public SeqData previous;
+ }
+ SeqData _seqDataStack;
+
private java.util.ArrayList _objectList;
}