Skip to content

Commit 02ea477

Browse files
jhoellerkkolman
authored andcommitted
CVE-2022-22970 - Refine CachedIntrospectionResults property introspection
Closes spring-projectsgh-28445 (cherry picked from commit 50177b1)
1 parent c32c216 commit 02ea477

File tree

2 files changed

+33
-5
lines changed

2 files changed

+33
-5
lines changed

spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.beans.IntrospectionException;
2121
import java.beans.Introspector;
2222
import java.beans.PropertyDescriptor;
23+
import java.net.URL;
2324
import java.security.ProtectionDomain;
2425
import java.util.Collections;
2526
import java.util.Iterator;
@@ -294,10 +295,12 @@ private CachedIntrospectionResults(Class<?> beanClass) throws BeansException {
294295
// Only allow all name variants of Class properties
295296
continue;
296297
}
297-
if (pd.getWriteMethod() == null && pd.getPropertyType() != null &&
298-
(ClassLoader.class.isAssignableFrom(pd.getPropertyType()) ||
299-
ProtectionDomain.class.isAssignableFrom(pd.getPropertyType()))) {
300-
// Ignore ClassLoader and ProtectionDomain read-only properties - no need to bind to those
298+
if (URL.class == beanClass && "content".equals(pd.getName())) {
299+
// Only allow URL attribute introspection, not content resolution
300+
continue;
301+
}
302+
if (pd.getWriteMethod() == null && isInvalidReadOnlyPropertyType(pd.getPropertyType())) {
303+
// Ignore read-only properties such as ClassLoader - no need to bind to those
301304
continue;
302305
}
303306
if (logger.isTraceEnabled()) {
@@ -335,6 +338,12 @@ private CachedIntrospectionResults(Class<?> beanClass) throws BeansException {
335338
}
336339
}
337340

341+
private boolean isInvalidReadOnlyPropertyType(Class<?> returnType) {
342+
return (returnType != null && (AutoCloseable.class.isAssignableFrom(returnType) ||
343+
ClassLoader.class.isAssignableFrom(returnType) ||
344+
ProtectionDomain.class.isAssignableFrom(returnType)));
345+
}
346+
338347
BeanInfo getBeanInfo() {
339348
return this.beanInfo;
340349
}

spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.tests.sample.beans.TestBean;
2626
import org.springframework.core.OverridingClassLoader;
2727
import org.springframework.core.io.DefaultResourceLoader;
28+
import org.springframework.core.io.UrlResource;
2829

2930
import static org.assertj.core.api.Assertions.assertThat;
3031
import static org.junit.Assert.*;
@@ -156,7 +157,7 @@ public void setPropertyTypeMismatch() {
156157
}
157158

158159
@Test
159-
public void propertyDescriptors() {
160+
public void propertyDescriptors() throws Exception {
160161
TestBean target = new TestBean();
161162
target.setSpouse(new TestBean());
162163
BeanWrapper accessor = createAccessor(target);
@@ -191,11 +192,29 @@ public void propertyDescriptors() {
191192
assertThat(accessor.isReadableProperty("class.package")).isFalse();
192193
assertThat(accessor.isReadableProperty("class.module")).isFalse();
193194
assertThat(accessor.isReadableProperty("class.classLoader")).isFalse();
195+
assertThat(accessor.isReadableProperty("class.name")).isTrue();
196+
assertThat(accessor.isReadableProperty("class.simpleName")).isTrue();
194197
assertThat(accessor.isReadableProperty("classLoader")).isTrue();
195198
assertThat(accessor.isWritableProperty("classLoader")).isTrue();
196199
OverridingClassLoader ocl = new OverridingClassLoader(getClass().getClassLoader());
197200
accessor.setPropertyValue("classLoader", ocl);
198201
assertThat(accessor.getPropertyValue("classLoader")).isSameAs(ocl);
202+
203+
accessor = createAccessor(new UrlResource("https://spring.io"));
204+
205+
assertThat(accessor.isReadableProperty("class.package")).isFalse();
206+
assertThat(accessor.isReadableProperty("class.module")).isFalse();
207+
assertThat(accessor.isReadableProperty("class.classLoader")).isFalse();
208+
assertThat(accessor.isReadableProperty("class.name")).isTrue();
209+
assertThat(accessor.isReadableProperty("class.simpleName")).isTrue();
210+
assertThat(accessor.isReadableProperty("URL.protocol")).isTrue();
211+
assertThat(accessor.isReadableProperty("URL.host")).isTrue();
212+
assertThat(accessor.isReadableProperty("URL.port")).isTrue();
213+
assertThat(accessor.isReadableProperty("URL.file")).isTrue();
214+
assertThat(accessor.isReadableProperty("URL.content")).isFalse();
215+
assertThat(accessor.isReadableProperty("inputStream")).isFalse();
216+
assertThat(accessor.isReadableProperty("filename")).isTrue();
217+
assertThat(accessor.isReadableProperty("description")).isTrue();
199218
}
200219

201220
@Test

0 commit comments

Comments
 (0)