From: Markus Koschany <apo@debian.org>
Date: Wed, 11 Jan 2023 13:57:58 +0100
Subject: CVE-2022-41966

Bug-Debian: https://bugs.debian.org/1027754
Origin: https://github.com/x-stream/xstream/commit/e9151f221b4969fb15b1e946d5d61dcdd459a391
---
 .../src/java/com/thoughtworks/xstream/XStream.java |  8 +++--
 .../security/AbstractSecurityException.java        | 29 ++++++++++++++++++
 .../security/InputManipulationException.java       | 27 +++++++++++++++++
 .../acceptance/SecurityVulnerabilityTest.java      | 35 +++++++++++++++++++++-
 4 files changed, 96 insertions(+), 3 deletions(-)
 create mode 100644 xstream/src/java/com/thoughtworks/xstream/security/AbstractSecurityException.java
 create mode 100644 xstream/src/java/com/thoughtworks/xstream/security/InputManipulationException.java

diff --git a/xstream/src/java/com/thoughtworks/xstream/XStream.java b/xstream/src/java/com/thoughtworks/xstream/XStream.java
index 129be1c..24c51cf 100644
--- a/xstream/src/java/com/thoughtworks/xstream/XStream.java
+++ b/xstream/src/java/com/thoughtworks/xstream/XStream.java
@@ -162,6 +162,7 @@ import com.thoughtworks.xstream.security.RegExpTypePermission;
 import com.thoughtworks.xstream.security.TypeHierarchyPermission;
 import com.thoughtworks.xstream.security.TypePermission;
 import com.thoughtworks.xstream.security.WildcardTypePermission;
+import com.thoughtworks.xstream.security.InputManipulationException;
 
 
 /**
@@ -1398,8 +1399,11 @@ public class XStream {
                     .println(
                         "Security framework of XStream not explicitly initialized, using predefined black list on your own risk.");
             }
-            return marshallingStrategy.unmarshal(root, reader, dataHolder, converterLookup, mapper);
-
+            try {
+                return marshallingStrategy.unmarshal(root, reader, dataHolder, converterLookup, mapper);
+            } catch (final StackOverflowError e) {
+                throw new InputManipulationException("Possible Denial of Service attack by Stack Overflow");
+            }
         } catch (ConversionException e) {
             Package pkg = getClass().getPackage();
             String version = pkg != null ? pkg.getImplementationVersion() : null;
diff --git a/xstream/src/java/com/thoughtworks/xstream/security/AbstractSecurityException.java b/xstream/src/java/com/thoughtworks/xstream/security/AbstractSecurityException.java
new file mode 100644
index 0000000..777765a
--- /dev/null
+++ b/xstream/src/java/com/thoughtworks/xstream/security/AbstractSecurityException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021, 2022 XStream Committers.
+ * All rights reserved.
+ *
+ * Created on 21. September 2021 by Joerg Schaible
+ */
+package com.thoughtworks.xstream.security;
+
+import com.thoughtworks.xstream.XStreamException;
+
+
+/**
+ * General base class for a Security Exception in XStream.
+ * 
+ * @author J&ouml;rg Schaible
+ * @since 1.4.19
+ */
+public abstract class AbstractSecurityException extends XStreamException {
+    private static final long serialVersionUID = 20210921L;
+
+    /**
+     * Constructs a SecurityException.
+     * @param message the exception message
+     * @since 1.4.19
+     */
+    public AbstractSecurityException(final String message) {
+        super(message);
+    }
+}
diff --git a/xstream/src/java/com/thoughtworks/xstream/security/InputManipulationException.java b/xstream/src/java/com/thoughtworks/xstream/security/InputManipulationException.java
new file mode 100644
index 0000000..80f492c
--- /dev/null
+++ b/xstream/src/java/com/thoughtworks/xstream/security/InputManipulationException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021, 2022 XStream Committers.
+ * All rights reserved.
+ *
+ * Created on 21. September 2021 by Joerg Schaible
+ */
+package com.thoughtworks.xstream.security;
+
+
+/**
+ * Class for a Security Exception assuming input manipulation in XStream.
+ * 
+ * @author J&ouml;rg Schaible
+ * @since 1.4.19
+ */
+public class InputManipulationException extends AbstractSecurityException {
+    private static final long serialVersionUID = 20210921L;
+
+    /**
+     * Constructs a SecurityException.
+     * @param message the exception message
+     * @since 1.4.19
+     */
+    public InputManipulationException(final String message) {
+        super(message);
+    }
+}
diff --git a/xstream/src/test/com/thoughtworks/acceptance/SecurityVulnerabilityTest.java b/xstream/src/test/com/thoughtworks/acceptance/SecurityVulnerabilityTest.java
index d387bcd..f21ea45 100644
--- a/xstream/src/test/com/thoughtworks/acceptance/SecurityVulnerabilityTest.java
+++ b/xstream/src/test/com/thoughtworks/acceptance/SecurityVulnerabilityTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2014, 2017, 2018, 2020, 2021 XStream Committers.
+ * Copyright (C) 2013, 2014, 2017, 2018, 2020, 2021, 2022 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -25,6 +25,8 @@ import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
 import com.thoughtworks.xstream.security.AnyTypePermission;
 import com.thoughtworks.xstream.security.ForbiddenClassException;
 import com.thoughtworks.xstream.security.ProxyTypePermission;
+import com.thoughtworks.xstream.security.InputManipulationException;
+
 
 
 /**
@@ -187,4 +189,35 @@ public class SecurityVulnerabilityTest extends AbstractAcceptanceTest {
             assertEquals("Unlimited reads of ByteArrayInputStream returning 0 bytes expected", 0, i);
         }
     }
+
+    public void testStackOverflowWithRecursiveHashSet() {
+        final String xml = ""
+            + "<set>\n"
+            + "  <set>\n"
+            + "    <set>\n"
+            + "      <set>\n"
+            + "        <set>\n"
+            + "          <set>\n"
+            + "            <string>a</string>\n"
+            + "          </set>\n"
+            + "          <set>\n"
+            + "            <string>b</string>\n"
+            + "          </set>\n"
+            + "        </set>\n"
+            + "        <set>\n"
+            + "          <string>c</string>\n"
+            + "          <set reference=\"../../../set/set[2]\"/>\n"
+            + "        </set>\n"
+            + "      </set>\n"
+            + "    </set>\n"
+            + "  </set>\n"
+            + "</set>";
+
+        try {
+            xstream.fromXML(xml);
+            fail("Thrown " + InputManipulationException.class.getName() + " expected");
+        } catch (final InputManipulationException e) {
+            assertTrue(e.getMessage().indexOf("Stack Overflow") >= 0);
+        }
+    }
 }
