MethodInvokeTypeProvider lazily invokes target method (avoiding deserialization exploits)
Issue: SPR-13656
This commit is contained in:
@@ -51,6 +51,7 @@ import org.springframework.util.ReflectionUtils;
|
|||||||
* {@link GenericArrayType#getGenericComponentType()}) will be automatically wrapped.
|
* {@link GenericArrayType#getGenericComponentType()}) will be automatically wrapped.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Juergen Hoeller
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
abstract class SerializableTypeWrapper {
|
abstract class SerializableTypeWrapper {
|
||||||
@@ -210,7 +211,7 @@ abstract class SerializableTypeWrapper {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link Serializable} {@link InvocationHandler} used by the Proxied {@link Type}.
|
* {@link Serializable} {@link InvocationHandler} used by the proxied {@link Type}.
|
||||||
* Provides serialization support and enhances any methods that return {@code Type}
|
* Provides serialization support and enhances any methods that return {@code Type}
|
||||||
* or {@code Type[]}.
|
* or {@code Type[]}.
|
||||||
*/
|
*/
|
||||||
@@ -373,21 +374,27 @@ abstract class SerializableTypeWrapper {
|
|||||||
|
|
||||||
private final int index;
|
private final int index;
|
||||||
|
|
||||||
private transient Object result;
|
private transient Method method;
|
||||||
|
|
||||||
|
private transient volatile Object result;
|
||||||
|
|
||||||
public MethodInvokeTypeProvider(TypeProvider provider, Method method, int index) {
|
public MethodInvokeTypeProvider(TypeProvider provider, Method method, int index) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
this.methodName = method.getName();
|
this.methodName = method.getName();
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.result = ReflectionUtils.invokeMethod(method, provider.getType());
|
this.method = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getType() {
|
public Type getType() {
|
||||||
if (this.result instanceof Type || this.result == null) {
|
Object result = this.result;
|
||||||
return (Type) this.result;
|
if (result == null) {
|
||||||
|
// Lazy invocation of the target method
|
||||||
|
result = ReflectionUtils.invokeMethod(this.method, this.provider.getType());
|
||||||
|
// Cache the result for further calls
|
||||||
|
this.result = result;
|
||||||
}
|
}
|
||||||
return ((Type[])this.result)[this.index];
|
return (result instanceof Type[] ? ((Type[]) result)[this.index] : (Type) result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -397,8 +404,8 @@ abstract class SerializableTypeWrapper {
|
|||||||
|
|
||||||
private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
|
private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
|
||||||
inputStream.defaultReadObject();
|
inputStream.defaultReadObject();
|
||||||
Method method = ReflectionUtils.findMethod(this.provider.getType().getClass(), this.methodName);
|
this.method = ReflectionUtils.findMethod(this.provider.getType().getClass(), this.methodName);
|
||||||
this.result = ReflectionUtils.invokeMethod(method, this.provider.getType());
|
Assert.state(this.method.getReturnType() == Type.class || this.method.getReturnType() == Type[].class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user