You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by el...@apache.org on 2026/04/24 08:02:58 UTC
(mina) 01/02: Added patch regarding whitelist bypassing backported from mina-2.2.X
This is an automated email from the ASF dual-hosted git repository.
elecharny pushed a commit to branch 2.0.X
in repository https://gitbox.apache.org/repos/asf/mina.git
commit 8b1dadb55b1d3f6b17f4ded10179e6b253ff1cc9
Author: Emmanuel Lécharny <em...@worteks.com>
AuthorDate: Thu Apr 23 10:51:03 2026 +0200
Added patch regarding whitelist bypassing backported from mina-2.2.X
---
.../apache/mina/core/buffer/AbstractIoBuffer.java | 47 ++++++------
.../org/apache/mina/core/buffer/IoBufferTest.java | 88 +++++++++++++++++++---
2 files changed, 103 insertions(+), 32 deletions(-)
diff --git a/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java b/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java
index 1a2463a6a..d5d54f9e5 100644
--- a/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java
+++ b/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java
@@ -88,6 +88,7 @@ public abstract class AbstractIoBuffer extends IoBuffer {
/** A mask for an int */
private static final long INT_MASK = 0xFFFFFFFFL;
+ /** A list of acceptable classes for deserialization */
private final List<ClassNameMatcher> acceptMatchers = new ArrayList<>();
/**
@@ -2182,6 +2183,14 @@ public abstract class AbstractIoBuffer extends IoBuffer {
case 1: // Serializable class
String className = readUTF();
+
+ // Only accept classes that are listed as acceptable
+ // Apply class filter BEFORE calling Class.forName
+ if (!acceptMatchers.stream().anyMatch(m -> m.matches(className))) {
+ throw new ClassNotFoundException("Class not in accept list " + className);
+ }
+
+ // Use initialize=false to prevent static block execution during class loading
Class<?> clazz = Class.forName(className, true, classLoader);
return ObjectStreamClass.lookup(clazz);
@@ -2193,32 +2202,24 @@ public abstract class AbstractIoBuffer extends IoBuffer {
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
- Class<?> clazz = desc.forClass();
+ String className = desc.getName();
- if (clazz == null) {
- String name = desc.getName();
+ // apply acceptMatchers filter before any Class.forName() call,
+ // regardless of whether forClass() is null or not
+ if (!acceptMatchers.stream().anyMatch(m -> m.matches(className))) {
+ throw new ClassNotFoundException("Class not in accept list " + className);
+ }
+
+ Class<?> clazz = desc.forClass();
- try {
- return Class.forName(name, false, classLoader);
- } catch (ClassNotFoundException ex) {
- return super.resolveClass(desc);
- }
- } else {
- boolean found = false;
- String className = desc.getName();
-
- for (ClassNameMatcher matcher : acceptMatchers) {
- if (matcher.matches(className)) {
- found = true;
- break;
- }
- }
+ if (clazz != null) {
+ return clazz;
+ }
- if (found) {
- return clazz;
- }
-
- throw new ClassNotFoundException();
+ try {
+ return Class.forName(className, false, classLoader);
+ } catch (ClassNotFoundException ex) {
+ return super.resolveClass(desc);
}
}
}) {
diff --git a/mina-core/src/test/java/org/apache/mina/core/buffer/IoBufferTest.java b/mina-core/src/test/java/org/apache/mina/core/buffer/IoBufferTest.java
index e969428a4..04c792afd 100644
--- a/mina-core/src/test/java/org/apache/mina/core/buffer/IoBufferTest.java
+++ b/mina-core/src/test/java/org/apache/mina/core/buffer/IoBufferTest.java
@@ -44,6 +44,7 @@ import java.util.List;
import org.apache.mina.core.buffer.matcher.RegexpClassNameMatcher;
import org.apache.mina.core.buffer.matcher.WildcardClassNameMatcher;
import org.apache.mina.util.Bar;
+import org.apache.mina.util.Foo;
import org.junit.Test;
/**
@@ -53,10 +54,10 @@ import org.junit.Test;
*/
public class IoBufferTest {
- private static interface NonserializableInterface {
+ private static interface NonSerializableInterface {
}
- public static class NonserializableClass {
+ public static class NonSerializableClass {
}
/**
@@ -388,8 +389,29 @@ public class IoBufferTest {
assertNotSame(o, o2);
}
+ @Test(expected=ClassNotFoundException.class)
+ public void testObjectSerializationReject() throws Exception {
+ IoBuffer buf = IoBuffer.allocate(16);
+ buf.setAutoExpand(true);
+ List<Object> o = new ArrayList<>();
+ o.add(new Date());
+ o.add(long.class);
+
+ // We don't accept type 0 class (long)
+ buf.accept(ArrayList.class.getName(), Date.class.getName());
+
+ // Test writing an object.
+ buf.putObject(o);
+
+ // Test reading an object.
+ buf.clear();
+
+ // The call should fail as long is not accepted
+ buf.getObject();
+ }
+
@Test
- public void testNonserializableClass() throws Exception {
+ public void testSerializableClass() throws Exception {
Class<?> c = String.class;
IoBuffer buffer = IoBuffer.allocate(16);
@@ -407,7 +429,7 @@ public class IoBufferTest {
}
@Test
- public void testNonserializableClassAcceptWildcard() throws Exception {
+ public void testSerializableClassAcceptWildcard() throws Exception {
Class<?> c = String.class;
IoBuffer buffer = IoBuffer.allocate(16);
@@ -444,8 +466,8 @@ public class IoBufferTest {
assertSame(c, o);
}
- @Test(expected=ClassNotFoundException.class)
- public void testNonserializableClassReject() throws Exception {
+ @Test(expected=BufferDataException.class)
+ public void testSerializableClassReject() throws Exception {
Class<?> c = String.class;
IoBuffer buffer = IoBuffer.allocate(16);
@@ -460,13 +482,43 @@ public class IoBufferTest {
}
@Test
- public void testNonserializableInterface() throws Exception {
- Class<?> c = NonserializableInterface.class;
+ public void testNonserializableInterfaceAccept() throws Exception {
+ Class<?> c = NonSerializableInterface.class;
+
+ IoBuffer buffer = IoBuffer.allocate(16);
+ buffer.setAutoExpand(true);
+ buffer.putObject(c);
+ buffer.accept(NonSerializableInterface.class.getName());
+
+ buffer.flip();
+ Object o = buffer.getObject();
+
+ assertEquals(c, o);
+ assertSame(c, o);
+ }
+
+ @Test(expected=ClassNotFoundException.class)
+ public void testNonserializableInterfaceReject() throws Exception {
+ Class<?> c = NonSerializableInterface.class;
+
+ IoBuffer buffer = IoBuffer.allocate(16);
+ buffer.setAutoExpand(true);
+ buffer.putObject(c);
+
+ buffer.flip();
+
+ // We must get an error
+ buffer.getObject();
+ }
+
+ @Test
+ public void testNonserializableClassAccept() throws Exception {
+ Class<?> c = NonSerializableClass.class;
IoBuffer buffer = IoBuffer.allocate(16);
buffer.setAutoExpand(true);
buffer.putObject(c);
- buffer.accept(NonserializableInterface.class.getName());
+ buffer.accept(NonSerializableClass.class.getName());
buffer.flip();
Object o = buffer.getObject();
@@ -475,6 +527,21 @@ public class IoBufferTest {
assertSame(c, o);
}
+
+ @Test(expected=ClassNotFoundException.class)
+ public void testNonserializableClassReject() throws Exception {
+ Class<?> c = NonSerializableClass.class;
+
+ IoBuffer buffer = IoBuffer.allocate(16);
+ buffer.setAutoExpand(true);
+ buffer.putObject(c);
+
+ buffer.flip();
+
+ // The call must fail
+ buffer.getObject();
+ }
+
@Test
public void testAllocate() throws Exception {
for (int i = 10; i < 1048576 * 2; i = i * 11 / 10) // increase by 10%
@@ -1007,7 +1074,10 @@ public class IoBufferTest {
// Test writing an object.
buf.putObject(expected);
+
+ // We must accept all the classes, including the parents.
buf.accept(Bar.class.getName());
+ buf.accept(Foo.class.getName());
// Test reading an object.
buf.clear();