Repository: logging-log4j2 Updated Branches: refs/heads/master 9f8f8f716 -> 12c159973
LOG4J2-2163 - Propogate filtering to subordinate ObjectInputStream Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/6e18c1bf Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/6e18c1bf Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/6e18c1bf Branch: refs/heads/master Commit: 6e18c1bfb5593237031d1db349a305b98960ccdd Parents: 9f8f8f7 Author: Ralph Goers <[email protected]> Authored: Wed Dec 27 15:33:03 2017 -0700 Committer: Ralph Goers <[email protected]> Committed: Wed Dec 27 15:33:03 2017 -0700 ---------------------------------------------------------------------- .../log4j/util/FilteredObjectInputStream.java | 100 +++++++++++++++++++ .../log4j/util/SortedArrayStringMap.java | 53 +++++++++- .../org/apache/logging/log4j/LoggerTest.java | 5 + .../logging/log4j/util/DeserializerHelper.java | 2 +- .../log4j/util/SortedArrayStringMapTest.java | 2 +- .../apache/logging/log4j/core/LogEventTest.java | 7 +- .../appender/mom/kafka/KafkaAppenderTest.java | 3 +- .../core/async/RingBufferLogEventTest.java | 3 +- .../log4j/core/impl/Log4jLogEventTest.java | 3 +- .../log4j/core/impl/MutableLogEventTest.java | 3 +- .../log4j/core/layout/SerializedLayoutTest.java | 5 +- 11 files changed, 172 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6e18c1bf/log4j-api/src/main/java/org/apache/logging/log4j/util/FilteredObjectInputStream.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/FilteredObjectInputStream.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/FilteredObjectInputStream.java new file mode 100644 index 0000000..df97fd2 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/FilteredObjectInputStream.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; + +/** + * Extended ObjectInputStream that only allows certain classes to be deserialized. + * + * @since 2.8.2 + */ +public class FilteredObjectInputStream extends ObjectInputStream { + + private static final List<String> REQUIRED_JAVA_CLASSES = Arrays.asList( + "java.math.BigDecimal", + "java.math.BigInteger", + // for Message delegate + "java.rmi.MarshalledObject", + "[B" + ); + + private static final List<String> REQUIRED_JAVA_PACKAGES = Arrays.asList( + "java.lang.", + "java.time", + "java.util.", + "org.apache.logging.log4j.", + "[Lorg.apache.logging.log4j." + ); + + private final Collection<String> allowedClasses; + + public FilteredObjectInputStream() throws IOException, SecurityException { + super(); + this.allowedClasses = new HashSet<>(); + } + + public FilteredObjectInputStream(InputStream in) throws IOException { + super(in); + this.allowedClasses = new HashSet<>(); + } + + public FilteredObjectInputStream(final Collection<String> allowedClasses) throws IOException, SecurityException { + super(); + this.allowedClasses = allowedClasses; + } + + public FilteredObjectInputStream(final InputStream in, final Collection<String> allowedClasses) throws IOException { + super(in); + this.allowedClasses = allowedClasses; + } + + public Collection<String> getAllowedClasses() { + return allowedClasses; + } + + @Override + protected Class<?> resolveClass(final ObjectStreamClass desc) throws IOException, ClassNotFoundException { + String name = desc.getName(); + if (!(isAllowedByDefault(name) || allowedClasses.contains(name))) { + throw new InvalidObjectException("Class is not allowed for deserialization: " + name); + } + return super.resolveClass(desc); + } + + private static boolean isAllowedByDefault(final String name) { + return isRequiredPackage(name) || REQUIRED_JAVA_CLASSES.contains(name); + } + + private static boolean isRequiredPackage(final String name) { + for (final String packageName : REQUIRED_JAVA_PACKAGES) { + if (name.startsWith(packageName)) { + return true; + } + } + return false; + } + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6e18c1bf/log4j-api/src/main/java/org/apache/logging/log4j/util/SortedArrayStringMap.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/SortedArrayStringMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/SortedArrayStringMap.java index 621d18a..c95aaab 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/SortedArrayStringMap.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/SortedArrayStringMap.java @@ -22,7 +22,13 @@ import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.StreamCorruptedException; +import java.io.WriteAbortedException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Arrays; +import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.Map; @@ -83,6 +89,24 @@ public class SortedArrayStringMap implements IndexedStringMap { */ private transient int size; + private static final Method setObjectInputFilter; + private static final Method getObjectInputFilter; + + static { + Method[] methods = ObjectInputStream.class.getMethods(); + Method setMethod = null; + Method getMethod = null; + for (Method method : methods) { + if (method.getName().equals("setObjectInputFilter")) { + setMethod = method;; + } else if (method.getName().equals("getObjectInputFilter")) { + getMethod = method; + } + } + setObjectInputFilter = setMethod; + getObjectInputFilter = getMethod; + } + /** * The next size value at which to resize (capacity * load factor). * @serial @@ -509,10 +533,30 @@ public class SortedArrayStringMap implements IndexedStringMap { } } - private static Object unmarshall(final byte[] data) throws IOException, ClassNotFoundException { + private static Object unmarshall(final byte[] data, ObjectInputStream inputStream) + throws IOException, ClassNotFoundException { final ByteArrayInputStream bin = new ByteArrayInputStream(data); - try (ObjectInputStream ois = new ObjectInputStream(bin)) { + Collection<String> allowedClasses = null; + ObjectInputStream ois; + if (inputStream instanceof FilteredObjectInputStream) { + allowedClasses = ((FilteredObjectInputStream) inputStream).getAllowedClasses(); + ois = new FilteredObjectInputStream(bin, allowedClasses); + } else { + try { + Object obj = getObjectInputFilter.invoke(inputStream); + if (obj == null) { + throw new StreamCorruptedException("An ObjectInputFilter must be provided"); + } + ois = new ObjectInputStream(bin); + setObjectInputFilter.invoke(ois, obj); + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new StreamCorruptedException("Unable to set ObjectInputFilter on stream"); + } + } + try { return ois.readObject(); + } finally { + ois.close(); } } @@ -534,6 +578,9 @@ public class SortedArrayStringMap implements IndexedStringMap { * deserialize it). */ private void readObject(final java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { + if (!(s instanceof FilteredObjectInputStream) || setObjectInputFilter != null) { + throw new IllegalArgumentException("readObject requires a FilteredObjectInputStream or an ObjectInputStream that accepts an ObjectInputFilter"); + } // Read in the threshold (ignored), and any hidden stuff s.defaultReadObject(); @@ -565,7 +612,7 @@ public class SortedArrayStringMap implements IndexedStringMap { keys[i] = (String) s.readObject(); try { final byte[] marshalledObject = (byte[]) s.readObject(); - values[i] = marshalledObject == null ? null : unmarshall(marshalledObject); + values[i] = marshalledObject == null ? null : unmarshall(marshalledObject, s); } catch (final Exception | LinkageError error) { handleSerializationException(error, i, keys[i]); values[i] = null; http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6e18c1bf/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java index f252cc9..2321c64 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/LoggerTest.java @@ -538,9 +538,14 @@ public class LoggerTest { ThreadContext.put("TestYear", Integer.valueOf(2010).toString()); logger.debug("Debug message"); + String testYear = ThreadContext.get("TestYear"); + assertNotNull("Test Year is null", testYear); + assertEquals("Incorrect test year: " + testYear, "2010", testYear); ThreadContext.clearMap(); logger.debug("Debug message"); assertEquals(2, results.size()); + System.out.println("Log line 1: " + results.get(0)); + System.out.println("log line 2: " + results.get(1)); assertTrue("Incorrect MDC: " + results.get(0), results.get(0).startsWith(" DEBUG Debug message {TestYear=2010}")); assertTrue("MDC not cleared?: " + results.get(1), http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6e18c1bf/log4j-api/src/test/java/org/apache/logging/log4j/util/DeserializerHelper.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/DeserializerHelper.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/DeserializerHelper.java index 20af4ec..930471d 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/util/DeserializerHelper.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/DeserializerHelper.java @@ -30,7 +30,7 @@ public class DeserializerHelper { final File file = new File(args[0]); ObjectInputStream in = null; try { - in = new ObjectInputStream(new FileInputStream(file)); + in = new FilteredObjectInputStream(new FileInputStream(file)); final Object result = in.readObject(); System.out.println(result); } catch (final Throwable t) { http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6e18c1bf/log4j-api/src/test/java/org/apache/logging/log4j/util/SortedArrayStringMapTest.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/SortedArrayStringMapTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/SortedArrayStringMapTest.java index 3392875..d97b7e2 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/util/SortedArrayStringMapTest.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/SortedArrayStringMapTest.java @@ -167,7 +167,7 @@ public class SortedArrayStringMapTest { private SortedArrayStringMap deserialize(final byte[] binary) throws IOException, ClassNotFoundException { final ByteArrayInputStream inArr = new ByteArrayInputStream(binary); - final ObjectInputStream in = new ObjectInputStream(inArr); + final ObjectInputStream in = new FilteredObjectInputStream(inArr); final SortedArrayStringMap result = (SortedArrayStringMap) in.readObject(); return result; } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6e18c1bf/log4j-core/src/test/java/org/apache/logging/log4j/core/LogEventTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/LogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/LogEventTest.java index 8a02d53..bd5ae3e 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/LogEventTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/LogEventTest.java @@ -27,6 +27,7 @@ import org.apache.logging.log4j.LoggingException; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.util.FilteredObjectInputStream; import org.junit.Ignore; import org.junit.Test; @@ -64,7 +65,7 @@ public class LogEventTest { oos.writeObject(event2); final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - final ObjectInputStream ois = new ObjectInputStream(bais); + final ObjectInputStream ois = new FilteredObjectInputStream(bais); try { ois.readObject(); } catch (final IOException ioe) { @@ -94,7 +95,7 @@ public class LogEventTest { oos.writeObject(event1); final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - final ObjectInputStream ois = new ObjectInputStream(bais); + final ObjectInputStream ois = new FilteredObjectInputStream(bais); final LogEvent actual = (LogEvent) ois.readObject(); assertNotEquals("Different event: nanoTime", copy, actual); @@ -121,7 +122,7 @@ public class LogEventTest { oos.writeObject(event1); final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - final ObjectInputStream ois = new ObjectInputStream(bais); + final ObjectInputStream ois = new FilteredObjectInputStream(bais); final LogEvent actual = (LogEvent) ois.readObject(); assertEquals("both zero nanoTime", event2, actual); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6e18c1bf/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java index 4932619..644a294 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java @@ -38,6 +38,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.junit.LoggerContextRule; import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.util.FilteredObjectInputStream; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; @@ -173,7 +174,7 @@ public class KafkaAppenderTest { private LogEvent deserializeLogEvent(final byte[] data) throws IOException, ClassNotFoundException { final ByteArrayInputStream bis = new ByteArrayInputStream(data); - try (ObjectInput ois = new ObjectInputStream(bis)) { + try (ObjectInput ois = new FilteredObjectInputStream(bis)) { return (LogEvent) ois.readObject(); } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6e18c1bf/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java index cbd6fbf..355e668 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java @@ -30,6 +30,7 @@ import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.ThreadContext.ContextStack; import org.apache.logging.log4j.categories.AsyncLoggers; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.util.FilteredObjectInputStream; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.message.Message; @@ -132,7 +133,7 @@ public class RingBufferLogEventTest { final ObjectOutputStream out = new ObjectOutputStream(baos); out.writeObject(evt); - final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())); + final ObjectInputStream in = new FilteredObjectInputStream(new ByteArrayInputStream(baos.toByteArray())); final RingBufferLogEvent other = (RingBufferLogEvent) in.readObject(); assertEquals(loggerName, other.getLoggerName()); assertEquals(marker, other.getMarker()); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6e18c1bf/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java index 069c34b..7fe3e6c 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java @@ -50,6 +50,7 @@ import org.apache.logging.log4j.message.ObjectMessage; import org.apache.logging.log4j.message.ReusableMessage; import org.apache.logging.log4j.message.ReusableObjectMessage; import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.util.FilteredObjectInputStream; import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.util.Strings; @@ -168,7 +169,7 @@ public class Log4jLogEventTest { private Log4jLogEvent deserialize(final byte[] binary) throws IOException, ClassNotFoundException { final ByteArrayInputStream inArr = new ByteArrayInputStream(binary); - final ObjectInputStream in = new ObjectInputStream(inArr); + final ObjectInputStream in = new FilteredObjectInputStream(inArr); final Log4jLogEvent result = (Log4jLogEvent) in.readObject(); return result; } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6e18c1bf/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java index 0d5fda3..5af5838 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java @@ -30,6 +30,7 @@ import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.util.FilteredObjectInputStream; import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.spi.MutableThreadContextStack; @@ -278,7 +279,7 @@ public class MutableLogEventTest { private Log4jLogEvent deserialize(final byte[] binary) throws IOException, ClassNotFoundException { final ByteArrayInputStream inArr = new ByteArrayInputStream(binary); - final ObjectInputStream in = new ObjectInputStream(inArr); + final ObjectInputStream in = new FilteredObjectInputStream(inArr); final Log4jLogEvent result = (Log4jLogEvent) in.readObject(); return result; } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6e18c1bf/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/SerializedLayoutTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/SerializedLayoutTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/SerializedLayoutTest.java index 09b0a0a..b7d590c 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/SerializedLayoutTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/SerializedLayoutTest.java @@ -38,6 +38,7 @@ import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.junit.ThreadContextRule; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.test.appender.ListAppender; +import org.apache.logging.log4j.util.FilteredObjectInputStream; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Rule; @@ -127,7 +128,7 @@ public class SerializedLayoutTest { int i = 0; for (final byte[] item : data) { final ByteArrayInputStream bais = new ByteArrayInputStream(item); - final ObjectInputStream ois = new ObjectInputStream(bais); + final ObjectInputStream ois = new FilteredObjectInputStream(bais); LogEvent event; try { event = (LogEvent) ois.readObject(); @@ -167,7 +168,7 @@ public class SerializedLayoutTest { testSerialization(); final File file = new File(DAT_PATH); final FileInputStream fis = new FileInputStream(file); - try (final ObjectInputStream ois = new ObjectInputStream(fis) ) { + try (final ObjectInputStream ois = new FilteredObjectInputStream(fis) ) { final LogEvent event = (LogEvent) ois.readObject(); assertNotNull(event); }
