Skip to content

Commit

Permalink
CVE-2022-22950 - Improve diagnostics in SpEL for large array creation
Browse files Browse the repository at this point in the history
Attempting to create a large array in a SpEL expression can result in
an OutOfMemoryError. Although the JVM recovers from that, the error
message is not very helpful to the user.

This commit improves the diagnostics in SpEL for large array creation
by throwing a SpelEvaluationException with a meaningful error message
in order to improve diagnostics for the user.

Closes spring-projectsgh-28257

(cherry picked from commit 90cfde9)
  • Loading branch information
sbrannen authored and kkolman committed Nov 1, 2022
1 parent 8674070 commit 12c3f41
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 4 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -31,6 +31,7 @@
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.0
*/
public enum SpelMessage {
Expand Down Expand Up @@ -255,7 +256,11 @@ public enum SpelMessage {

/** @since 4.3.17 */
FLAWED_PATTERN(Kind.ERROR, 1073,
"Failed to efficiently evaluate pattern ''{0}'': consider redesigning it");
"Failed to efficiently evaluate pattern ''{0}'': consider redesigning it"),

/** @since 5.2.20 */
MAX_ARRAY_ELEMENTS_THRESHOLD_EXCEEDED(Kind.ERROR, 1075,
"Array declares too many elements, exceeding the threshold of ''{0}''");


private final Kind kind;
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -51,12 +51,20 @@
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.0
*/
public class ConstructorReference extends SpelNodeImpl {

private boolean isArrayConstructor = false;

/**
* Maximum number of elements permitted in an array declaration, applying
* to one-dimensional as well as multi-dimensional arrays.
* @since 5.2.20
*/
private static final int MAX_ARRAY_ELEMENTS = 256 * 1024; // 256K

private SpelNodeImpl[] dimensions;

// TODO is this caching safe - passing the expression around will mean this executor is also being passed around
Expand Down Expand Up @@ -256,14 +264,19 @@ private TypedValue createArray(ExpressionState state) throws EvaluationException
if (this.dimensions.length == 1) {
TypedValue o = this.dimensions[0].getTypedValue(state);
int arraySize = ExpressionUtils.toInt(typeConverter, o);
checkNumElements(arraySize);
newArray = Array.newInstance(componentType, arraySize);
}
else {
// Multi-dimensional - hold onto your hat!
int[] dims = new int[this.dimensions.length];
long numElements = 1;
for (int d = 0; d < this.dimensions.length; d++) {
TypedValue o = this.dimensions[d].getTypedValue(state);
dims[d] = ExpressionUtils.toInt(typeConverter, o);
int arraySize = ExpressionUtils.toInt(typeConverter, o);
dims[d] = arraySize;
numElements *= arraySize;
checkNumElements(numElements);
}
newArray = Array.newInstance(componentType, dims);
}
Expand Down Expand Up @@ -323,6 +336,13 @@ else if (arrayTypeCode == TypeCode.SHORT) {
return new TypedValue(newArray);
}

private void checkNumElements(long numElements) {
if (numElements >= MAX_ARRAY_ELEMENTS) {
throw new SpelEvaluationException(getStartPosition(),
SpelMessage.MAX_ARRAY_ELEMENTS_THRESHOLD_EXCEEDED, MAX_ARRAY_ELEMENTS);
}
}

private void populateReferenceTypeArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
InlineList initializer, Class<?> componentType) {

Expand Down
Expand Up @@ -83,6 +83,10 @@ public void errorCases() {
evaluateAndCheckError("new char[3]{'a','c','d','e'}", SpelMessage.INITIALIZER_LENGTH_INCORRECT);
evaluateAndCheckError("new char[2]{'hello','world'}", SpelMessage.TYPE_CONVERSION_ERROR);
evaluateAndCheckError("new String('a','c','d')", SpelMessage.CONSTRUCTOR_INVOCATION_PROBLEM);

int threshold = 256 * 1024; // ConstructorReference.MAX_ARRAY_ELEMENTS
evaluateAndCheckError("new int[T(java.lang.Integer).MAX_VALUE]", SpelMessage.MAX_ARRAY_ELEMENTS_THRESHOLD_EXCEEDED, 0, threshold);
evaluateAndCheckError("new int[1024 * 1024][1024 * 1024]", SpelMessage.MAX_ARRAY_ELEMENTS_THRESHOLD_EXCEEDED, 0, threshold);
}

@Test
Expand Down

0 comments on commit 12c3f41

Please sign in to comment.