[apache-log4j2] 01/01: Fixed CVE-2017-5645: Remote code execution with the TCP/UDP socket server (Closes: #860489)

Emmanuel Bourg ebourg-guest at moszumanska.debian.org
Tue Apr 18 12:46:10 UTC 2017


This is an automated email from the git hooks/post-receive script.

ebourg-guest pushed a commit to branch master
in repository apache-log4j2.

commit 799b96337bcf909193aa76c6090ba511c05b64f6
Author: Emmanuel Bourg <ebourg at apache.org>
Date:   Tue Apr 18 14:44:43 2017 +0200

    Fixed CVE-2017-5645: Remote code execution with the TCP/UDP socket server (Closes: #860489)
---
 debian/changelog                   |  10 ++
 debian/patches/CVE-2017-5645.patch | 253 +++++++++++++++++++++++++++++++++++++
 debian/patches/series              |   1 +
 3 files changed, 264 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index 5ad7abc..4fb99f5 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
+apache-log4j2 (2.7-2) unstable; urgency=medium
+
+  * Team upload.
+  * Fixed CVE-2017-5645: When using the TCP socket server or UDP socket server
+    to receive serialized log events from another application, a specially
+    crafted binary payload can be sent that, when deserialized, can execute
+    arbitrary code (Closes: #860489)
+
+ -- Emmanuel Bourg <ebourg at apache.org>  Tue, 18 Apr 2017 14:30:00 +0200
+
 apache-log4j2 (2.7-1) unstable; urgency=medium
 
   * Team upload.
diff --git a/debian/patches/CVE-2017-5645.patch b/debian/patches/CVE-2017-5645.patch
new file mode 100644
index 0000000..d5e8327
--- /dev/null
+++ b/debian/patches/CVE-2017-5645.patch
@@ -0,0 +1,253 @@
+Description: CVE-2017-5645: When using the TCP socket server or UDP socket
+ server to receive serialized log events from another application,
+ a specially crafted binary payload can be sent that, when deserialized,
+ can execute arbitrary code.
+ .
+ This patch adds 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.
+Origin: backport, https://github.com/apache/logging-log4j2/commit/5dcc192
+Bug: https://issues.apache.org/jira/browse/LOG4J2-1863
+Bug-Debian: https://bugs.debian.org/860489
+--- 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
+@@ -25,6 +25,8 @@
+ import java.net.MalformedURLException;
+ import java.net.URI;
+ import java.net.URL;
++import java.util.Collections;
++import java.util.List;
+ import java.util.Objects;
+ 
+ import org.apache.logging.log4j.LogManager;
+@@ -71,6 +73,9 @@
+                 "-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;
+         }
+@@ -102,6 +107,14 @@
+         void setLocalBindAddress(InetAddress localBindAddress) {
+             this.localBindAddress = localBindAddress;
+         }
++
++        List<String> getAllowedClasses() {
++            return allowedClasses == null ? Collections.<String>emptyList() : allowedClasses;
++        }
++
++        void setAllowedClasses(final List<String> allowedClasses) {
++            this.allowedClasses = allowedClasses;
++        }
+     }
+ 
+     /**
+--- 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,15 +19,34 @@
+ 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 {
+@@ -40,6 +59,6 @@
+ 
+     @Override
+     public ObjectInputStream wrapStream(final InputStream inputStream) throws IOException {
+-        return new ObjectInputStream(inputStream);
++        return new FilteredObjectInputStream(inputStream, allowedClasses);
+     }
+ }
+--- 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
+@@ -26,6 +26,8 @@
+ import java.net.InetAddress;
+ import java.net.ServerSocket;
+ import java.net.Socket;
++import java.util.Collections;
++import java.util.List;
+ import java.nio.charset.Charset;
+ import java.util.Map;
+ import java.util.concurrent.ConcurrentHashMap;
+@@ -154,9 +156,26 @@
+      */
+     public static TcpSocketServer<ObjectInputStream> createSerializedSocketServer(final int port, final int backlog,
+             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);
+     }
+ 
+@@ -191,8 +210,8 @@
+         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 = new Log4jThread(socketServer);
+         serverThread.start();
+         if (cla.isInteractive()) {
+--- 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
+@@ -26,6 +26,7 @@
+ 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.Log4jThread;
+@@ -66,6 +67,21 @@
+     }
+ 
+     /**
++     * 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
+@@ -95,7 +111,7 @@
+             ConfigurationFactory.setConfigurationFactory(new ServerConfigurationFactory(cla.getConfigLocation()));
+         }
+         final UdpSocketServer<ObjectInputStream> socketServer = UdpSocketServer
+-                .createSerializedSocketServer(cla.getPort());
++                .createSerializedSocketServer(cla.getPort(), cla.getAllowedClasses());
+         final Thread serverThread = new Log4jThread(socketServer);
+         serverThread.start();
+         if (cla.isInteractive()) {
+--- /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);
++    }
++
++}
diff --git a/debian/patches/series b/debian/patches/series
index a5195ad..257f7b6 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,4 @@
 01-disable-kafka-appender.patch
 02-jackson-compatibility.patch
 03-mongodb-compatibility.patch
+CVE-2017-5645.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/apache-log4j2.git



More information about the pkg-java-commits mailing list