Repository: logging-log4j2
Updated Branches:
  refs/heads/master 5aff929bb -> 5dcc19215


[LOG4J2-1863] Add class filtering to AbstractSocketServer

This allows a whitelist of class names to be specified to configure
which classes are allowed to be deserialized in both TcpSocketServer and
UdpSocketServer.


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/5dcc1921
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/5dcc1921
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/5dcc1921

Branch: refs/heads/master
Commit: 5dcc19215827db29c993d0305ee2b0d8dd05939d
Parents: 5aff929
Author: Matt Sicker <[email protected]>
Authored: Sat Mar 11 16:01:46 2017 -0600
Committer: Matt Sicker <[email protected]>
Committed: Sun Apr 2 12:41:20 2017 -0500

----------------------------------------------------------------------
 .../core/net/server/AbstractSocketServer.java   | 13 ++++
 .../server/ObjectInputStreamLogEventBridge.java | 23 ++++++-
 .../log4j/core/net/server/TcpSocketServer.java  | 25 +++++++-
 .../log4j/core/net/server/UdpSocketServer.java  | 18 +++++-
 .../core/util/FilteredObjectInputStream.java    | 67 ++++++++++++++++++++
 5 files changed, 140 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5dcc1921/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/AbstractSocketServer.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/AbstractSocketServer.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/AbstractSocketServer.java
index 9836694..923d3f4 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/AbstractSocketServer.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/AbstractSocketServer.java
@@ -26,6 +26,8 @@ import java.io.InputStreamReader;
 import java.net.InetAddress;
 import java.net.URI;
 import java.net.URL;
+import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
 
 import com.beust.jcommander.Parameter;
@@ -70,6 +72,9 @@ public abstract class AbstractSocketServer<T extends 
InputStream> extends LogEve
                 "-a" }, converter = InetAddressConverter.class, description = 
"Server socket local bind address.")
         private InetAddress localBindAddress;
 
+        @Parameter(names = {"--classes", "-C"}, description = "Additional 
classes to allow deserialization")
+        private List<String> allowedClasses;
+
         String getConfigLocation() {
             return configLocation;
         }
@@ -101,6 +106,14 @@ public abstract class AbstractSocketServer<T extends 
InputStream> extends LogEve
         void setLocalBindAddress(final InetAddress localBindAddress) {
             this.localBindAddress = localBindAddress;
         }
+
+        List<String> getAllowedClasses() {
+            return allowedClasses == null ? Collections.<String>emptyList() : 
allowedClasses;
+        }
+
+        void setAllowedClasses(final List<String> allowedClasses) {
+            this.allowedClasses = allowedClasses;
+        }
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5dcc1921/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/ObjectInputStreamLogEventBridge.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/ObjectInputStreamLogEventBridge.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/ObjectInputStreamLogEventBridge.java
index 059f069..a27b1cb 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/ObjectInputStreamLogEventBridge.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/ObjectInputStreamLogEventBridge.java
@@ -19,18 +19,37 @@ package org.apache.logging.log4j.core.net.server;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.ObjectInputStream;
+import java.util.Collections;
+import java.util.List;
 
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.LogEventListener;
+import org.apache.logging.log4j.core.util.FilteredObjectInputStream;
 
 /**
  * Reads and logs serialized {@link LogEvent} objects from an {@link 
ObjectInputStream}.
  */
 public class ObjectInputStreamLogEventBridge extends 
AbstractLogEventBridge<ObjectInputStream> {
 
+    private final List<String> allowedClasses;
+
+    public ObjectInputStreamLogEventBridge() {
+        this(Collections.<String>emptyList());
+    }
+
+    /**
+     * Constructs an ObjectInputStreamLogEventBridge with additional allowed 
classes to deserialize.
+     *
+     * @param allowedClasses class names to also allow for deserialization
+     * @since 2.8.2
+     */
+    public ObjectInputStreamLogEventBridge(final List<String> allowedClasses) {
+        this.allowedClasses = allowedClasses;
+    }
+
     @Override
     public void logEvents(final ObjectInputStream inputStream, final 
LogEventListener logEventListener)
-            throws IOException {
+        throws IOException {
         try {
             logEventListener.log((LogEvent) inputStream.readObject());
         } catch (final ClassNotFoundException e) {
@@ -40,6 +59,6 @@ public class ObjectInputStreamLogEventBridge extends 
AbstractLogEventBridge<Obje
 
     @Override
     public ObjectInputStream wrapStream(final InputStream inputStream) throws 
IOException {
-        return new ObjectInputStream(inputStream);
+        return new FilteredObjectInputStream(inputStream, allowedClasses);
     }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5dcc1921/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/TcpSocketServer.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/TcpSocketServer.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/TcpSocketServer.java
index 68ac1ba..b5ce211 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/TcpSocketServer.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/TcpSocketServer.java
@@ -24,6 +24,8 @@ import java.io.OptionalDataException;
 import java.net.InetAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -148,9 +150,26 @@ public class TcpSocketServer<T extends InputStream> 
extends AbstractSocketServer
      */
     public static TcpSocketServer<ObjectInputStream> 
createSerializedSocketServer(final int port, final int backlog,
             final InetAddress localBindAddress) throws IOException {
+        return createSerializedSocketServer(port, backlog, localBindAddress, 
Collections.<String>emptyList());
+    }
+
+    /**
+     * Creates a socket server that reads serialized log events.
+     *
+     * @param port the port to listen
+     * @param localBindAddress The server socket's local bin address
+     * @param allowedClasses additional class names to allow for 
deserialization
+     * @return a new a socket server
+     * @throws IOException
+     *         if an I/O error occurs when opening the socket.
+     * @since 2.8.2
+     */
+    public static TcpSocketServer<ObjectInputStream> 
createSerializedSocketServer(
+        final int port, final int backlog, final InetAddress localBindAddress, 
final List<String> allowedClasses
+    ) throws IOException {
         LOGGER.entry(port);
         final TcpSocketServer<ObjectInputStream> socketServer = new 
TcpSocketServer<>(port, backlog, localBindAddress,
-                new ObjectInputStreamLogEventBridge());
+                new ObjectInputStreamLogEventBridge(allowedClasses));
         return LOGGER.exit(socketServer);
     }
 
@@ -185,8 +204,8 @@ public class TcpSocketServer<T extends InputStream> extends 
AbstractSocketServer
         if (cla.getConfigLocation() != null) {
             ConfigurationFactory.setConfigurationFactory(new 
ServerConfigurationFactory(cla.getConfigLocation()));
         }
-        final TcpSocketServer<ObjectInputStream> socketServer = TcpSocketServer
-                .createSerializedSocketServer(cla.getPort(), cla.getBacklog(), 
cla.getLocalBindAddress());
+        final TcpSocketServer<ObjectInputStream> socketServer = 
TcpSocketServer.createSerializedSocketServer(
+            cla.getPort(), cla.getBacklog(), cla.getLocalBindAddress(), 
cla.getAllowedClasses());
         final Thread serverThread = socketServer.startNewThread();
         if (cla.isInteractive()) {
             socketServer.awaitTermination(serverThread);

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5dcc1921/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/UdpSocketServer.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/UdpSocketServer.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/UdpSocketServer.java
index ed04f69..e761c3b 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/UdpSocketServer.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/UdpSocketServer.java
@@ -24,6 +24,7 @@ import java.io.ObjectInputStream;
 import java.io.OptionalDataException;
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
+import java.util.List;
 
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.util.BasicCommandLineArguments;
@@ -64,6 +65,21 @@ public class UdpSocketServer<T extends InputStream> extends 
AbstractSocketServer
     }
 
     /**
+     * Creates a socket server that reads serialized log events.
+     *
+     * @param port the port to listen
+     * @param allowedClasses additional classes to allow for deserialization
+     * @return a new a socket server
+     * @throws IOException if an I/O error occurs when opening the socket.
+     * @since 2.8.2
+     */
+    public static UdpSocketServer<ObjectInputStream> 
createSerializedSocketServer(final int port,
+                                                                               
   final List<String> allowedClasses)
+        throws IOException {
+        return new UdpSocketServer<>(port, new 
ObjectInputStreamLogEventBridge(allowedClasses));
+    }
+
+    /**
      * Creates a socket server that reads XML log events.
      * 
      * @param port
@@ -93,7 +109,7 @@ public class UdpSocketServer<T extends InputStream> extends 
AbstractSocketServer
             ConfigurationFactory.setConfigurationFactory(new 
ServerConfigurationFactory(cla.getConfigLocation()));
         }
         final UdpSocketServer<ObjectInputStream> socketServer = UdpSocketServer
-                .createSerializedSocketServer(cla.getPort());
+                .createSerializedSocketServer(cla.getPort(), 
cla.getAllowedClasses());
         final Thread serverThread = socketServer.startNewThread();
         if (cla.isInteractive()) {
             socketServer.awaitTermination(serverThread);

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5dcc1921/log4j-core/src/main/java/org/apache/logging/log4j/core/util/FilteredObjectInputStream.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/FilteredObjectInputStream.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/FilteredObjectInputStream.java
new file mode 100644
index 0000000..57cc31c
--- /dev/null
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/FilteredObjectInputStream.java
@@ -0,0 +1,67 @@
+/*
+ * 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.core.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.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(
+        // for StandardLevel
+        "java.lang.Enum",
+        // for location information
+        "java.lang.StackTraceElement",
+        // for Message delegate
+        "java.rmi.MarshalledObject",
+        "[B"
+    );
+
+    private final Collection<String> allowedClasses;
+
+    public FilteredObjectInputStream(final InputStream in, final 
Collection<String> allowedClasses) throws IOException {
+        super(in);
+        this.allowedClasses = 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 name.startsWith("org.apache.logging.log4j.") ||
+            name.startsWith("[Lorg.apache.logging.log4j.") ||
+            REQUIRED_JAVA_CLASSES.contains(name);
+    }
+
+}

Reply via email to