Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@
import java.util.Arrays;
import java.util.Collection;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.util.Constants;
import org.apache.logging.log4j.util.FilteredObjectInputStream;
import org.apache.logging.log4j.test.junit.SerialUtil;

/**
* Utiities for serialization tests.
Expand Down Expand Up @@ -114,15 +113,12 @@ public static Object deserializeStream(final String witness) throws Exception {
}

private static ObjectInputStream newObjectInputStream(final InputStream in) throws IOException {
if (Constants.JAVA_MAJOR_VERSION == 8) {
// FilteredObjectInputStream's default allow-list covers `org.apache.logging.log4j.` but
// not the `org.apache.log4j.` 1.2-compatibility namespace, so we have to enumerate the
// 1.2 classes that the tests in this module deserialize on Java 8.
final Collection<String> allowedLog4j12Classes =
Arrays.asList("org.apache.log4j.Level", "org.apache.log4j.LevelTest$CustomLevel");
return new FilteredObjectInputStream(in, allowedLog4j12Classes);
}
return new ObjectInputStream(in);
// The default allow-list covers `org.apache.logging.log4j.` but
// not the `org.apache.log4j.` 1.2-compatibility namespace, so we have to enumerate the
// 1.2 classes that the tests in this module deserialize.
final Collection<String> allowedLog4j12Classes =
Arrays.asList("org.apache.log4j.Level", "org.apache.log4j.LevelTest$CustomLevel");
return SerialUtil.getObjectInputStream(in, allowedLog4j12Classes);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public static <T extends Serializable> Matcher<T> serializesRoundTrip(final Matc

/**
* Same as {@link #serializesRoundTrip(Matcher)} but extends the default deserialization
* allow-list on Java 8 (see {@link SerialUtil#deserialize(byte[], Collection)}).
* allowlist (see {@link SerialUtil#deserialize(byte[], Collection)}).
*/
public static <T extends Serializable> Matcher<T> serializesRoundTrip(
final Matcher<T> matcher, final Collection<String> allowedExtraClasses) {
Expand All @@ -64,8 +64,8 @@ public static Matcher<? super Serializable> serializesRoundTrip() {
}

/**
* Same as {@link #serializesRoundTrip()} but extends the default deserialization allow-list on
* Java 8 (see {@link SerialUtil#deserialize(byte[], Collection)}).
* Same as {@link #serializesRoundTrip()} but extends the default deserialization allow-list
* (see {@link SerialUtil#deserialize(byte[], Collection)}).
*/
public static Matcher<? super Serializable> serializesRoundTrip(final Collection<String> allowedExtraClasses) {
return serializesRoundTrip(any(Serializable.class), allowedExtraClasses);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import org.apache.logging.log4j.test.internal.annotation.SuppressFBWarnings;
Expand All @@ -35,6 +36,34 @@
*/
public class SerialUtil {

// On Java 9+ streams are filtered with `DefaultObjectInputFilter`, which must be accessed reflectively.
private static final Method createFilter;
private static final Method newDefaultObjectInputFilter;
private static final Method setObjectInputFilter;

static {
Method createFilterMethod = null;
Method newInstanceMethod = null;
Method setFilterMethod = null;
if (Constants.JAVA_MAJOR_VERSION != 8) {
try {
final Class<?> filterClass = Class.forName("java.io.ObjectInputFilter");
createFilterMethod =
Class.forName("java.io.ObjectInputFilter$Config").getMethod("createFilter", String.class);
newInstanceMethod = Class.forName("org.apache.logging.log4j.util.internal.DefaultObjectInputFilter")
.getMethod("newInstance", filterClass);
setFilterMethod = ObjectInputStream.class.getMethod("setObjectInputFilter", filterClass);
} catch (final ReflectiveOperationException e) {
createFilterMethod = null;
newInstanceMethod = null;
// setFilterMethod is already null
}
}
createFilter = createFilterMethod;
newDefaultObjectInputFilter = newInstanceMethod;
setObjectInputFilter = setFilterMethod;
}

private SerialUtil() {}

/**
Expand Down Expand Up @@ -76,12 +105,10 @@ public static <T> T deserialize(final byte[] data) {
}

/**
* Deserialize an object from the specified byte array using a {@link FilteredObjectInputStream}
* extended with the supplied allow-list (Java 8 only — Java 9+ uses the JVM's serialization
* filter, so the allow-list is ignored).
* Deserialize an object from the specified byte array using a stream that applies Log4j's
* deserialization allow-list, extended with the supplied extra classes.
* @param data byte array representing the serialized object
* @param allowedExtraClasses fully-qualified class names to add to {@link
* FilteredObjectInputStream}'s default allow-list on Java 8
* @param allowedExtraClasses fully-qualified class names to add to the default allow-list
* @return the deserialized object
*/
@SuppressWarnings("unchecked")
Expand All @@ -106,8 +133,8 @@ public static ObjectInputStream getObjectInputStream(final byte[] data) throws I
}

/**
* Creates an {@link ObjectInputStream} adapted to the current Java version, extended with the
* supplied allow-list on Java 8.
* Creates an {@link ObjectInputStream} adapted to the current Java version, applying Log4j's
* deserialization allow-list extended with the supplied extra classes.
*/
@SuppressFBWarnings("OBJECT_DESERIALIZATION")
public static ObjectInputStream getObjectInputStream(
Expand All @@ -127,14 +154,24 @@ public static ObjectInputStream getObjectInputStream(final InputStream stream) t
}

/**
* Creates an {@link ObjectInputStream} adapted to the current Java version, extended with the
* supplied allow-list on Java 8.
* Creates an {@link ObjectInputStream} adapted to the current Java version, applying Log4j's
* deserialization allowlist extended with the supplied extra classes.
*/
@SuppressFBWarnings("OBJECT_DESERIALIZATION")
public static ObjectInputStream getObjectInputStream(
final InputStream stream, final Collection<String> allowedExtraClasses) throws IOException {
return Constants.JAVA_MAJOR_VERSION == 8
? new FilteredObjectInputStream(stream, allowedExtraClasses)
: new ObjectInputStream(stream);
if (Constants.JAVA_MAJOR_VERSION == 8 || newDefaultObjectInputFilter == null) {
return new FilteredObjectInputStream(stream, allowedExtraClasses);
}
final ObjectInputStream ois = new ObjectInputStream(stream);
try {
final Object extraClassesFilter = allowedExtraClasses.isEmpty()
? null
: createFilter.invoke(null, String.join(";", allowedExtraClasses));
setObjectInputFilter.invoke(ois, newDefaultObjectInputFilter.invoke(null, extraClassesFilter));
} catch (final ReflectiveOperationException e) {
throw new IllegalStateException("Unable to install the deserialization filter", e);
}
return ois;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="https://logging.apache.org/xml/ns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
https://logging.apache.org/xml/ns
https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
type="changed">
<issue id="4270" link="https://github.com/apache/logging-log4j2/pull/4270"/>
<description format="asciidoc">
The `SerialUtil` test helper now applies the deserialization allowlist also on Java 9 and later.
</description>
</entry>
Loading