Skip to content

Commit

Permalink
Fixes handling of annotation wrapper length overflows.
Browse files Browse the repository at this point in the history
  • Loading branch information
tgregg committed Jul 3, 2024
1 parent f8e1205 commit 2a46423
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 3 deletions.
12 changes: 9 additions & 3 deletions src/main/java/com/amazon/ion/impl/IonCursorBinary.java
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,9 @@ private long availableAt(long index) {
* @return true if the buffer has sufficient capacity; otherwise, false.
*/
private boolean ensureCapacity(long minimumNumberOfBytesRequired) {
if (minimumNumberOfBytesRequired < 0) {
throw new IonException("The number of bytes required cannot be represented in a Java long.");
}
if (freeSpaceAt(offset) >= minimumNumberOfBytesRequired) {
// No need to shift any bytes or grow the buffer.
return true;
Expand Down Expand Up @@ -809,18 +812,21 @@ private boolean uncheckedReadAnnotationWrapperHeader_1_0(IonTypeID valueTid) {
throw new IonException("Malformed data: declared length exceeds the number of bytes remaining in the stream.");
}
byte b = buffer[(int) peekIndex++];
int annotationsLength;
long annotationsLength;
if (b < 0) {
annotationsLength = (b & LOWER_SEVEN_BITS_BITMASK);
} else {
annotationsLength = (int) uncheckedReadVarUInt_1_0(b);
annotationsLength = uncheckedReadVarUInt_1_0(b);
}
annotationSequenceMarker.startIndex = peekIndex;
annotationSequenceMarker.endIndex = annotationSequenceMarker.startIndex + annotationsLength;
peekIndex = annotationSequenceMarker.endIndex;
if (peekIndex >= endIndex) {
throw new IonException("Annotation wrapper must wrap a value.");
}
if (peekIndex < 0) {
throw new IonException("Malformed data: declared length exceeds the number of bytes remaining in the stream.");
}
return false;
}

Expand Down Expand Up @@ -855,7 +861,7 @@ private boolean slowReadAnnotationWrapperHeader_1_0(IonTypeID valueTid) {
}
// Record the post-length index in a value that will be shifted in the event the buffer needs to refill.
setMarker(peekIndex + valueLength, valueMarker);
int annotationsLength = (int) slowReadVarUInt_1_0();
long annotationsLength = slowReadVarUInt_1_0();
if (annotationsLength < 0) {
return true;
}
Expand Down
50 changes: 50 additions & 0 deletions src/test/java/com/amazon/ion/impl/IonCursorBinaryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -467,4 +467,54 @@ public void expectIncompleteIvmToFailCleanly(boolean constructFromBytes) {
}
cursor.close();
}

@ParameterizedTest(name = "constructFromBytes={0}")
@ValueSource(booleans = {true, false})
public void annotationSequenceLengthExceedsJavaLong(boolean constructFromBytes) {
try (
IonCursorBinary cursor = initializeCursor(
constructFromBytes,
0xE0, 0x01, 0x00, 0xEA, // IVM
0xEA, // Annotation wrapper, length 10
0x01, 0x16, 0x76, 0x76, 0x76, 0x76, 0x3F, 0x3F, 0x76, 0x76, 0xF3, // Annotation sequence length > Long.MAX_VALUE
0x9E // The start of the annotation sequence
)
) {
assertThrows(IonException.class, cursor::nextValue);
}
}

@ParameterizedTest(name = "constructFromBytes={0}")
@ValueSource(booleans = {true, false})
public void annotationSequenceLengthPlusCurrentIndexExceedsJavaLong(boolean constructFromBytes) {
try (
IonCursorBinary cursor = initializeCursor(
constructFromBytes,
0xE0, 0x01, 0x00, 0xEA, // IVM
0xEA, // Annotation wrapper, length 10
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0xFF, // Annotation sequence length = Long.MAX_VALUE
0x9E // The start of the annotation sequence
)
) {
assertThrows(IonException.class, cursor::nextValue);
}
}

@ParameterizedTest(name = "constructFromBytes={0}")
@ValueSource(booleans = {true, false})
public void annotationWrapperLengthPlusCurrentIndexExceedsJavaLong(boolean constructFromBytes) {
try (
IonCursorBinary cursor = initializeCursor(
constructFromBytes,
0xE0, 0x01, 0x00, 0xEA, // IVM
0xEE, // Annotation wrapper, variable length
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0xFF, // Annotation wrapper length = Long.MAX_VALUE
0x81, // Annotation sequence length = 1
0x83, // SID 3
0x9E // The start of the wrapped value
)
) {
assertThrows(IonException.class, cursor::nextValue);
}
}
}

0 comments on commit 2a46423

Please sign in to comment.