Codebase list libxstream-java / c194602 debian / patches / CVE-2021-21341-to-CVE-2021-21351.patch
c194602

Tree @c194602 (Download .tar.gz)

CVE-2021-21341-to-CVE-2021-21351.patch @c194602raw · history · blame

From: Markus Koschany <apo@debian.org>
Date: Sat, 3 Apr 2021 21:15:39 +0200
Subject: CVE-2021-21341-to-CVE-2021-21351

Bug-Debian: https://bugs.debian.org/985843
Origin: https://github.com/x-stream/xstream/commit/d5e51177634afea7213b9dc2d21f101d2e258db9
---
 .../src/java/com/thoughtworks/xstream/XStream.java | 32 +++++++++++++---
 .../acceptance/SecurityVulnerabilityTest.java      | 43 ++++++++++++++++++++++
 2 files changed, 70 insertions(+), 5 deletions(-)

diff --git a/xstream/src/java/com/thoughtworks/xstream/XStream.java b/xstream/src/java/com/thoughtworks/xstream/XStream.java
index 8415da2..b5e43af 100644
--- a/xstream/src/java/com/thoughtworks/xstream/XStream.java
+++ b/xstream/src/java/com/thoughtworks/xstream/XStream.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2003, 2004, 2005, 2006 Joe Walnes.
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2020 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2020, 2021 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -36,7 +36,6 @@ import java.net.URL;
 import java.nio.charset.Charset;
 import java.text.DecimalFormatSymbols;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.BitSet;
 import java.util.Calendar;
 import java.util.Collection;
@@ -335,9 +334,14 @@ public class XStream {
 
     private static final String ANNOTATION_MAPPER_TYPE = "com.thoughtworks.xstream.mapper.AnnotationMapper";
     private static final Pattern IGNORE_ALL = Pattern.compile(".*");
+    private static final Pattern GETTER_SETTER_REFLECTION = Pattern.compile(".*\\$GetterSetterReflection");
+    private static final Pattern PRIVILEGED_GETTER = Pattern.compile(".*\\$PrivilegedGetter");
     private static final Pattern LAZY_ITERATORS = Pattern.compile(".*\\$LazyIterator");
+    private static final Pattern JAXWS_ITERATORS = Pattern.compile(".*\\$ServiceNameIterator");
+    private static final Pattern JAVAFX_OBSERVABLE_LIST__ = Pattern.compile(
+        "javafx\\.collections\\.ObservableList\\$.*");
     private static final Pattern JAVAX_CRYPTO = Pattern.compile("javax\\.crypto\\..*");
-    private static final Pattern JAXWS_FILE_STREAM = Pattern.compile(".*\\.ReadAllStream\\$FileStream");
+    private static final Pattern BCEL_CL = Pattern.compile(".*\\.bcel\\..*\\.util\\.ClassLoader");
 
     /**
      * Constructs a default XStream.
@@ -647,12 +651,30 @@ public class XStream {
             "java.beans.EventHandler", //
             "java.lang.ProcessBuilder", //
             "javax.imageio.ImageIO$ContainsFilter", //
-            "jdk.nashorn.internal.objects.NativeString" });
-        denyTypesByRegExp(new Pattern[]{LAZY_ITERATORS, JAVAX_CRYPTO, JAXWS_FILE_STREAM});
+            "jdk.nashorn.internal.objects.NativeString", //
+            "com.sun.corba.se.impl.activation.ServerTableEntry", //
+            "com.sun.tools.javac.processing.JavacProcessingEnvironment$NameProcessIterator", //
+            "sun.awt.datatransfer.DataTransferer$IndexOrderComparator", //
+            "sun.swing.SwingLazyValue"});
+        denyTypesByRegExp(new Pattern[]{
+            LAZY_ITERATORS, GETTER_SETTER_REFLECTION, PRIVILEGED_GETTER, JAVAX_CRYPTO, JAXWS_ITERATORS,
+            JAVAFX_OBSERVABLE_LIST__, BCEL_CL});
+        denyTypeHierarchy(InputStream.class);
+        denyTypeHierarchyDynamically("java.nio.channels.Channel");
+        denyTypeHierarchyDynamically("javax.activation.DataSource");
+        denyTypeHierarchyDynamically("javax.sql.rowset.BaseRowSet");
+
         allowTypeHierarchy(Exception.class);
         securityInitialized = false;
     }
 
+    private void denyTypeHierarchyDynamically(String className) {
+        Class type = JVM.loadClassForName(className);
+        if (type != null) {
+            denyTypeHierarchy(type);
+        }
+    }
+
     /**
      * Setup the security framework of a XStream instance.
      * <p>
diff --git a/xstream/src/test/com/thoughtworks/acceptance/SecurityVulnerabilityTest.java b/xstream/src/test/com/thoughtworks/acceptance/SecurityVulnerabilityTest.java
index da5f861..9da221c 100644
--- a/xstream/src/test/com/thoughtworks/acceptance/SecurityVulnerabilityTest.java
+++ b/xstream/src/test/com/thoughtworks/acceptance/SecurityVulnerabilityTest.java
@@ -11,6 +11,7 @@
 package com.thoughtworks.acceptance;
 
 import java.beans.EventHandler;
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -282,4 +283,46 @@ public class SecurityVulnerabilityTest extends AbstractAcceptanceTest {
             }
         }
     }
+
+    public void testCannotInjectManipulatedByteArryInputStream() {
+        xstream.alias("bais", ByteArrayInputStream.class);
+        System.out.println(Integer.MAX_VALUE);
+        final String xml = ""
+            + "<bais>\n"
+            + "  <buf></buf>\n"
+            + "  <pos>-2147483648</pos>\n"
+            + "  <mark>0</mark>\n"
+            + "  <count>0</count>\n"
+            + "</bais>";
+
+        try {
+            xstream.fromXML(xml);
+            fail("Thrown " + ForbiddenClassException.class.getName() + " expected");
+        } catch (final ForbiddenClassException e) {
+            assertEquals(e.getMessage(),ByteArrayInputStream.class.getName());
+        }
+    }
+
+    public void testExplicitlyUnmarshalEndlessByteArryInputStream() {
+        xstream.alias("bais", ByteArrayInputStream.class);
+        xstream.allowTypes(new Class[]{ByteArrayInputStream.class});
+
+        final String xml = ""
+            + "<bais>\n"
+            + "  <buf></buf>\n"
+            + "  <pos>-2147483648</pos>\n"
+            + "  <mark>0</mark>\n"
+            + "  <count>0</count>\n"
+            + "</bais>";
+        
+        final byte[] data = new byte[10];
+        final ByteArrayInputStream bais = (ByteArrayInputStream)xstream.fromXML(xml);
+        int i = 5;
+        while(bais.read(data, 0, 10) == 0) {
+            if (--i == 0) {
+                break;
+            }
+        }
+        assertEquals("Unlimited reads of ByteArrayInputStream returning 0 bytes expected", 0, i);
+    }
 }