From: Markus Koschany <apo@debian.org> Date: Tue, 28 Mar 2017 14:51:54 +0200 Subject: CVE-2017-5929 Bug-Debian: https://bugs.debian.org/857343 Origin: https://github.com/qos-ch/logback/commit/f46044b805bca91efe5fd6afe52257cd02f775f8 --- .../logback/classic/net/SimpleSocketServer.java | 1 - .../server/LogbackClassicSerializationHelper.java | 28 +++++++++++++ .../core/net/HardenedObjectInputStream.java | 48 ++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 logback-classic/src/main/java/ch/qos/logback/classic/net/server/LogbackClassicSerializationHelper.java create mode 100644 logback-core/src/main/java/ch/qos/logback/core/net/HardenedObjectInputStream.java diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/net/SimpleSocketServer.java b/logback-classic/src/main/java/ch/qos/logback/classic/net/SimpleSocketServer.java index 13bf6f7..17fda2a 100644 --- a/logback-classic/src/main/java/ch/qos/logback/classic/net/SimpleSocketServer.java +++ b/logback-classic/src/main/java/ch/qos/logback/classic/net/SimpleSocketServer.java @@ -14,7 +14,6 @@ package ch.qos.logback.classic.net; import java.io.IOException; -import java.lang.reflect.Constructor; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/net/server/LogbackClassicSerializationHelper.java b/logback-classic/src/main/java/ch/qos/logback/classic/net/server/LogbackClassicSerializationHelper.java new file mode 100644 index 0000000..00a974f --- /dev/null +++ b/logback-classic/src/main/java/ch/qos/logback/classic/net/server/LogbackClassicSerializationHelper.java @@ -0,0 +1,28 @@ +package ch.qos.logback.classic.net.server; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.helpers.BasicMarker; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.LoggerContextVO; +import ch.qos.logback.classic.spi.LoggingEventVO; +import ch.qos.logback.classic.spi.ThrowableProxyVO; + +public class LogbackClassicSerializationHelper { + + + + static public List<String> getWhilelist() { + List<String> whitelist = new ArrayList<String>(); + whitelist.add(LoggingEventVO.class.getName()); + whitelist.add(LoggerContextVO.class.getName()); + whitelist.add(ThrowableProxyVO.class.getName()); + whitelist.add(StackTraceElement.class.getName()); + whitelist.add(BasicMarker.class.getName()); + whitelist.add(BasicMarker.class.getName()); + whitelist.add(Logger.class.getName()); + return whitelist; + } +} diff --git a/logback-core/src/main/java/ch/qos/logback/core/net/HardenedObjectInputStream.java b/logback-core/src/main/java/ch/qos/logback/core/net/HardenedObjectInputStream.java new file mode 100644 index 0000000..439e2bd --- /dev/null +++ b/logback-core/src/main/java/ch/qos/logback/core/net/HardenedObjectInputStream.java @@ -0,0 +1,48 @@ +package ch.qos.logback.core.net; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * + * @author Ceki Gülcü + * @since 1.2.0 + */ +public class HardenedObjectInputStream extends ObjectInputStream { + + List<String> whitelistedClassNames; + String[] javaPackages = new String[] {"java.lang", "java.util"}; + + public HardenedObjectInputStream(InputStream in, List<String> whilelist) throws IOException { + super(in); + this.whitelistedClassNames = Collections.synchronizedList(new ArrayList<String>(whilelist)); + } + + @Override + protected Class<?> resolveClass(ObjectStreamClass anObjectStreamClass) throws IOException, ClassNotFoundException { + String incomingClassName = anObjectStreamClass.getName(); + if(!isWhitelisted(incomingClassName)) { + throw new InvalidClassException("Unauthorized deserialization attempt", anObjectStreamClass.getName()); + } + + return super.resolveClass(anObjectStreamClass); + } + + private boolean isWhitelisted(String incomingClassName) { + for(int i = 0; i < javaPackages.length; i++) { + if(incomingClassName.startsWith(javaPackages[i])) + return true; + } + for(String className: whitelistedClassNames) { + if(incomingClassName.equals(className)) + return true; + } + return false; + } +}