From fdd9f7d3de0d7ccf2f9979bcd09fbf3e6a0c881a Mon Sep 17 00:00:00 2001
From: joehni <joerg.schaible@gmx.de>
Date: Wed, 18 Sep 2024 20:19:13 +0200
Subject: [PATCH] Detect input manipulation in
 c.t.x.io.binary.BinaryStreamReader.

Origin:
https://github.com/x-stream/xstream/commit/fdd9f7d3de0d7ccf2f9979bcd09fbf3e6a0c881a
---
 .../xstream/io/binary/BinaryStreamReader.java  | 18 ++++++++++++------
 .../xstream/io/binary/BinaryStreamTest.java    | 17 ++++++++++++++++-
 2 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/xstream/src/java/com/thoughtworks/xstream/io/binary/BinaryStreamReader.java b/xstream/src/java/com/thoughtworks/xstream/io/binary/BinaryStreamReader.java
index 2839651..cd870cd 100644
--- a/xstream/src/java/com/thoughtworks/xstream/io/binary/BinaryStreamReader.java
+++ b/xstream/src/java/com/thoughtworks/xstream/io/binary/BinaryStreamReader.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2006 Joe Walnes.
- * Copyright (C) 2006, 2007, 2011, 2013 XStream Committers.
+ * Copyright (C) 2006, 2007, 2011, 2013, 2024 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -15,6 +15,7 @@ import com.thoughtworks.xstream.converters.ErrorWriter;
 import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamReader;
 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
 import com.thoughtworks.xstream.io.StreamException;
+import com.thoughtworks.xstream.security.InputManipulationException;
 
 import java.io.DataInputStream;
 import java.io.IOException;
@@ -150,15 +151,20 @@ public class BinaryStreamReader implements ExtendedHierarchicalStreamReader {
     private Token readToken() {
         if (pushback == null) {
             try {
-                Token token = tokenFormatter.read(in);
-                switch (token.getType()) {
+                boolean mapping = false;
+                do {
+                    final Token token = tokenFormatter.read(in);
+                    switch (token.getType()) {
                     case Token.TYPE_MAP_ID_TO_VALUE:
                         idRegistry.put(token.getId(), token.getValue());
-                        return readToken(); // Next one please.
+                        mapping ^= true;
+                        continue; // Next one please.
                     default:
                         return token;
-                }
-            } catch (IOException e) {
+                    }
+                } while (mapping);
+                throw new InputManipulationException("Binary stream will never have two mapping tokens in sequence");
+            } catch (final IOException e) {
                 throw new StreamException(e);
             }
         } else {
diff --git a/xstream/src/test/com/thoughtworks/xstream/io/binary/BinaryStreamTest.java b/xstream/src/test/com/thoughtworks/xstream/io/binary/BinaryStreamTest.java
index a01065a..d93954f 100644
--- a/xstream/src/test/com/thoughtworks/xstream/io/binary/BinaryStreamTest.java
+++ b/xstream/src/test/com/thoughtworks/xstream/io/binary/BinaryStreamTest.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2006 Joe Walnes.
- * Copyright (C) 2006, 2007, 2011, 2015, 2016, 2021 XStream Committers.
+ * Copyright (C) 2006, 2007, 2011, 2015, 2016, 2021, 2024 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -17,10 +17,12 @@ import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
 import com.thoughtworks.xstream.io.copy.HierarchicalStreamCopier;
 import com.thoughtworks.xstream.io.xml.AbstractXMLReaderTest;
 import com.thoughtworks.xstream.io.xml.MXParserDriver;
+import com.thoughtworks.xstream.security.InputManipulationException;
 
 import java.io.ByteArrayOutputStream;
 import java.io.StringReader;
 import java.io.ByteArrayInputStream;
+import java.io.InputStream;
 
 public class BinaryStreamTest extends AbstractXMLReaderTest {
 
@@ -89,4 +91,17 @@ public class BinaryStreamTest extends AbstractXMLReaderTest {
         }
     }
 
+    public void testHandleMaliciousInputsOfIdMappingTokens() {
+        // Insert two successive id mapping tokens into the stream
+        final byte[] byteArray = new byte[8];
+        byteArray[0] = byteArray[4] = 10;
+        byteArray[1] = byteArray[5] = -127;
+
+        final InputStream in = new ByteArrayInputStream(byteArray);
+        try {
+            new BinaryStreamReader(in);
+            fail("Thrown " + InputManipulationException.class.getName() + " expected");
+        } catch (final InputManipulationException e) {
+        }
+    }
 }
-- 
2.47.0

