Browse Source

MethodInvokeTypeProvider lazily invokes target method (avoiding deserialization exploits)

Issue: SPR-13656
pull/916/head
Juergen Hoeller 9 years ago
parent
commit
ea2843ecc0
  1. 23
      spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java

23
spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java

@ -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);
} }
} }

Loading…
Cancel
Save