From 9c782b45be4abdafb7e17481e24e7354c2acd1eb Mon Sep 17 00:00:00 2001 From: Ceki Gulcu Date: Mon, 27 Nov 2023 10:48:00 +0100 Subject: [PATCH] prevent DOS attacks using on malicious serialized input Signed-off-by: Ceki Gulcu --- .../logback/classic/spi/LoggingEventVO.java | 9 ++++++++ .../core/net/HardenedObjectInputStream.java | 22 +++++++++++++------ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggingEventVO.java b/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggingEventVO.java index 2b62ddfe40..4d3e2da0f0 100644 --- a/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggingEventVO.java +++ b/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggingEventVO.java @@ -14,6 +14,7 @@ package ch.qos.logback.classic.spi; import java.io.IOException; +import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; @@ -28,6 +29,7 @@ import ch.qos.logback.classic.Level; // http://www.riehle.org/computer-science/research/1998/ubilab-tr-1998-10-1.html +// See also the paper https://www.riehle.org/computer-science/research/1998/ubilab-tr-1998-10-1.pdf /** * A read-only and serializable implementation of {@link ILoggingEvent}. @@ -41,6 +43,7 @@ public class LoggingEventVO implements ILoggingEvent, Serializable { private static final int NULL_ARGUMENT_ARRAY = -1; private static final String NULL_ARGUMENT_ARRAY_ELEMENT = "NULL_ARGUMENT_ARRAY_ELEMENT"; + private static final int ARGUMENT_ARRAY_DESERIALIZATION_LIMIT = 128; private String threadName; private String loggerName; @@ -203,6 +206,12 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE level = Level.toLevel(levelInt); int argArrayLen = in.readInt(); + + // Prevent DOS attacks via large or negative arrays + if (argArrayLen < 0 || argArrayLen > ARGUMENT_ARRAY_DESERIALIZATION_LIMIT) { + throw new InvalidObjectException("Argument array length is invalid: " + argArrayLen); + } + if (argArrayLen != NULL_ARGUMENT_ARRAY) { argumentArray = new String[argArrayLen]; for (int i = 0; i < argArrayLen; i++) { 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 index 45f2b3444f..185d8fbd73 100755 --- 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 @@ -16,6 +16,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InvalidClassException; +import java.io.ObjectInputFilter; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; import java.util.ArrayList; @@ -36,20 +37,27 @@ */ public class HardenedObjectInputStream extends ObjectInputStream { - final List whitelistedClassNames; - final static String[] JAVA_PACKAGES = new String[] { "java.lang", "java.util" }; + final private List whitelistedClassNames; + final private static String[] JAVA_PACKAGES = new String[] { "java.lang", "java.util" }; + final private static int DEPTH_LIMIT = 16; + final private static int ARRAY_LIMIT = 10000; - public HardenedObjectInputStream(InputStream in, String[] whilelist) throws IOException { + public HardenedObjectInputStream(InputStream in, String[] whitelist) throws IOException { super(in); - + this.initObjectFilter(); this.whitelistedClassNames = new ArrayList(); - if (whilelist != null) { - for (int i = 0; i < whilelist.length; i++) { - this.whitelistedClassNames.add(whilelist[i]); + if (whitelist != null) { + for (int i = 0; i < whitelist.length; i++) { + this.whitelistedClassNames.add(whitelist[i]); } } } + private void initObjectFilter() { + this.setObjectInputFilter(ObjectInputFilter.Config.createFilter( + "maxarray=" + ARRAY_LIMIT + ";maxdepth=" + DEPTH_LIMIT + ";" + )); + } public HardenedObjectInputStream(InputStream in, List whitelist) throws IOException { super(in);