From ea4609eca531916ac347686c048bebdb7b4b6e0d Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 2 Jun 2017 14:37:35 +0200 Subject: [PATCH] Backport fix for CVE-2017-5645 --- .../apache/log4j/FilteredObjectInputStream.java | 65 ++++++++++++++++++++++ src/main/java/org/apache/log4j/net/SocketNode.java | 17 +++++- 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/apache/log4j/FilteredObjectInputStream.java diff --git a/src/main/java/org/apache/log4j/FilteredObjectInputStream.java b/src/main/java/org/apache/log4j/FilteredObjectInputStream.java new file mode 100644 index 0000000..b9ef20c --- /dev/null +++ b/src/main/java/org/apache/log4j/FilteredObjectInputStream.java @@ -0,0 +1,65 @@ +/* + * 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.log4j; + +import java.io.FileOutputStream; +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.List; + +/** + * Extended ObjectInputStream that only allows certain classes to be deserialized. + * + * Backported from 2.8.2 + */ +public class FilteredObjectInputStream extends ObjectInputStream { + + private static final List REQUIRED_JAVA_CLASSES = Arrays.asList(new String[] { + // Types of non-trainsient fields of LoggingEvent + "java.lang.String", + "java.util.Hashtable", + // ThrowableInformation + "[Ljava.lang.String;" + }); + + private final Collection allowedClasses; + + public FilteredObjectInputStream(final InputStream in, final Collection allowedClasses) throws IOException { + super(in); + this.allowedClasses = allowedClasses; + } + + 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 name.startsWith("org.apache.log4j.") || + name.startsWith("[Lorg.apache.log4j.") || + REQUIRED_JAVA_CLASSES.contains(name); + } + +} diff --git a/src/main/java/org/apache/log4j/net/SocketNode.java b/src/main/java/org/apache/log4j/net/SocketNode.java index e977f13..f95bb10 100644 --- a/src/main/java/org/apache/log4j/net/SocketNode.java +++ b/src/main/java/org/apache/log4j/net/SocketNode.java @@ -22,6 +22,10 @@ import java.io.IOException; import java.io.InterruptedIOException; import java.io.ObjectInputStream; import java.net.Socket; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import org.apache.log4j.FilteredObjectInputStream; import org.apache.log4j.Logger; import org.apache.log4j.spi.LoggerRepository; @@ -53,8 +57,9 @@ public class SocketNode implements Runnable { this.socket = socket; this.hierarchy = hierarchy; try { - ois = new ObjectInputStream( - new BufferedInputStream(socket.getInputStream())); + ois = new FilteredObjectInputStream( + new BufferedInputStream(socket.getInputStream()), + getAllowedClasses()); } catch(InterruptedIOException e) { Thread.currentThread().interrupt(); logger.error("Could not open ObjectInputStream to "+socket, e); @@ -65,6 +70,14 @@ public class SocketNode implements Runnable { } } + private Collection getAllowedClasses() { + Collection allowedClasses = new ArrayList(); + String property = System.getProperty("org.apache.log4j.net.allowedClasses"); + if (property != null) + allowedClasses.addAll(Arrays.asList(property.split(","))); + return allowedClasses; + } + //public //void finalize() { //System.err.println("-------------------------Finalize called"); -- 2.9.4