Skip to content

Commit c612b2f

Browse files
committed
add deseialization filter by reflction, enable commented out test case
Signed-off-by: Ceki Gulcu <[email protected]>
1 parent d1bf54f commit c612b2f

File tree

2 files changed

+72
-36
lines changed

2 files changed

+72
-36
lines changed

logback-core/src/main/java/ch/qos/logback/core/net/HardenedObjectInputStream.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,16 @@
1313
*/
1414
package ch.qos.logback.core.net;
1515

16+
import ch.qos.logback.core.util.EnvUtil;
17+
1618
import java.io.IOException;
1719
import java.io.InputStream;
1820
import java.io.InvalidClassException;
21+
import java.io.ObjectInputFilter;
1922
import java.io.ObjectInputStream;
2023
import java.io.ObjectStreamClass;
24+
import java.lang.reflect.InvocationTargetException;
25+
import java.lang.reflect.Method;
2126
import java.util.ArrayList;
2227
import java.util.List;
2328

@@ -43,6 +48,7 @@ public class HardenedObjectInputStream extends ObjectInputStream {
4348

4449
public HardenedObjectInputStream(InputStream in, String[] whitelist) throws IOException {
4550
super(in);
51+
this.initObjectFilter();
4652
this.whitelistedClassNames = new ArrayList<String>();
4753
if (whitelist != null) {
4854
for (int i = 0; i < whitelist.length; i++) {
@@ -54,11 +60,36 @@ public HardenedObjectInputStream(InputStream in, String[] whitelist) throws IOEx
5460

5561
public HardenedObjectInputStream(InputStream in, List<String> whitelist) throws IOException {
5662
super(in);
57-
63+
this.initObjectFilter();
5864
this.whitelistedClassNames = new ArrayList<String>();
5965
this.whitelistedClassNames.addAll(whitelist);
6066
}
6167

68+
private void initObjectFilter() {
69+
70+
// invoke the following code by reflection
71+
// this.setObjectInputFilter(ObjectInputFilter.Config.createFilter(
72+
// "maxarray=" + ARRAY_LIMIT + ";maxdepth=" + DEPTH_LIMIT + ";"
73+
// ));
74+
if(EnvUtil.isJDK9OrHigher()) {
75+
try {
76+
ClassLoader classLoader = this.getClass().getClassLoader();
77+
78+
Class oifClass = classLoader.loadClass("java.io.ObjectInputFilter");
79+
Class oifConfigClass = classLoader.loadClass("java.io.ObjectInputFilter$Config");
80+
Method setObjectInputFilterMethod = this.getClass().getMethod("setObjectInputFilter", oifClass);
81+
82+
Method createFilterMethod = oifConfigClass.getMethod("createFilter", String.class);
83+
Object filter = createFilterMethod.invoke(null, "maxarray=" + ARRAY_LIMIT + ";maxdepth=" + DEPTH_LIMIT + ";");
84+
setObjectInputFilterMethod.invoke(this, filter);
85+
} catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException | InvocationTargetException e) {
86+
// this code should be unreachable
87+
throw new RuntimeException("Failed to initialize object filter", e);
88+
}
89+
90+
}
91+
}
92+
6293
@Override
6394
protected Class<?> resolveClass(ObjectStreamClass anObjectStreamClass) throws IOException, ClassNotFoundException {
6495

logback-core/src/test/java/ch/qos/logback/core/net/HardenedObjectInputStreamTest.java

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@
33
import java.io.ByteArrayInputStream;
44
import java.io.ByteArrayOutputStream;
55
import java.io.IOException;
6+
import java.io.InvalidClassException;
67
import java.io.ObjectOutputStream;
8+
import java.util.HashSet;
9+
import java.util.Set;
710

811
import org.junit.jupiter.api.AfterEach;
912
import org.junit.jupiter.api.BeforeEach;
13+
import org.junit.jupiter.api.Disabled;
1014
import org.junit.jupiter.api.Test;
1115

1216
import static org.junit.jupiter.api.Assertions.assertEquals;
17+
import static org.junit.jupiter.api.Assertions.assertNotNull;
18+
import static org.junit.jupiter.api.Assertions.assertThrows;
1319

1420
public class HardenedObjectInputStreamTest {
1521

@@ -53,39 +59,38 @@ private void writeObject(ObjectOutputStream oos, Object o) throws IOException {
5359
oos.close();
5460
}
5561

56-
// @Ignore
57-
// @Test
58-
// public void denialOfService() throws ClassNotFoundException, IOException {
59-
// ByteArrayInputStream bis = new ByteArrayInputStream(payload());
60-
// inputStream = new HardenedObjectInputStream(bis, whitelist);
61-
// try {
62-
// Set set = (Set) inputStream.readObject();
63-
// assertNotNull(set);
64-
// } finally {
65-
// inputStream.close();
66-
// }
67-
// }
68-
//
69-
// private byte[] payload() throws IOException {
70-
// Set root = buildEvilHashset();
71-
// return serialize(root);
72-
// }
73-
//
74-
// private Set buildEvilHashset() {
75-
// Set root = new HashSet();
76-
// Set s1 = root;
77-
// Set s2 = new HashSet();
78-
// for (int i = 0; i < 100; i++) {
79-
// Set t1 = new HashSet();
80-
// Set t2 = new HashSet();
81-
// t1.add("foo"); // make it not equal to t2
82-
// s1.add(t1);
83-
// s1.add(t2);
84-
// s2.add(t1);
85-
// s2.add(t2);
86-
// s1 = t1;
87-
// s2 = t2;
88-
// }
89-
// return root;
90-
// }
62+
@Test
63+
public void denialOfService() throws ClassNotFoundException, IOException {
64+
ByteArrayInputStream bis = new ByteArrayInputStream(payload());
65+
inputStream = new HardenedObjectInputStream(bis, whitelist);
66+
try {
67+
assertThrows(InvalidClassException.class, () -> inputStream.readObject());
68+
} finally {
69+
inputStream.close();
70+
}
71+
}
72+
73+
private byte[] payload() throws IOException {
74+
Set root = buildEvilHashset();
75+
writeObject(oos, root);
76+
return bos.toByteArray();
77+
}
78+
79+
private Set buildEvilHashset() {
80+
Set root = new HashSet();
81+
Set s1 = root;
82+
Set s2 = new HashSet();
83+
for (int i = 0; i < 100; i++) {
84+
Set t1 = new HashSet();
85+
Set t2 = new HashSet();
86+
t1.add("foo"); // make it not equal to t2
87+
s1.add(t1);
88+
s1.add(t2);
89+
s2.add(t1);
90+
s2.add(t2);
91+
s1 = t1;
92+
s2 = t2;
93+
}
94+
return root;
95+
}
9196
}

0 commit comments

Comments
 (0)