210 lines
8.7 KiB
Diff
210 lines
8.7 KiB
Diff
From e6fae590cf2a758c47cd5a17f9bf3780ce62c986 Mon Sep 17 00:00:00 2001
|
|
From: Marcono1234 <Marcono1234@users.noreply.github.com>
|
|
Date: Wed, 13 Oct 2021 19:14:57 +0200
|
|
Subject: [PATCH] Prevent Java deserialization of internal classes (#1991)
|
|
|
|
Adversaries might be able to forge data which can be abused for DoS attacks.
|
|
These classes are already writing a replacement JDK object during serialization for a long time, so this change should not cause any issues.
|
|
|
|
---
|
|
.../gson/internal/LazilyParsedNumber.java | 8 +++++++
|
|
.../gson/internal/LinkedHashTreeMap.java | 8 +++++++
|
|
.../google/gson/internal/LinkedTreeMap.java | 8 +++++++
|
|
.../gson/internal/LazilyParsedNumberTest.java | 18 ++++++++++++++++
|
|
.../gson/internal/LinkedHashTreeMapTest.java | 21 +++++++++++++++++++
|
|
.../gson/internal/LinkedTreeMapTest.java | 20 ++++++++++++++++++
|
|
6 files changed, 83 insertions(+)
|
|
|
|
diff --git a/gson/src/main/java/com/google/gson/internal/LazilyParsedNumber.java b/gson/src/main/java/com/google/gson/internal/LazilyParsedNumber.java
|
|
index 3669af7..6138dff 100644
|
|
--- a/gson/src/main/java/com/google/gson/internal/LazilyParsedNumber.java
|
|
+++ b/gson/src/main/java/com/google/gson/internal/LazilyParsedNumber.java
|
|
@@ -15,6 +15,9 @@
|
|
*/
|
|
package com.google.gson.internal;
|
|
|
|
+import java.io.IOException;
|
|
+import java.io.InvalidObjectException;
|
|
+import java.io.ObjectInputStream;
|
|
import java.io.ObjectStreamException;
|
|
import java.math.BigDecimal;
|
|
|
|
@@ -77,6 +80,11 @@ public final class LazilyParsedNumber extends Number {
|
|
return new BigDecimal(value);
|
|
}
|
|
|
|
+ private void readObject(ObjectInputStream in) throws IOException {
|
|
+ // Don't permit directly deserializing this class; writeReplace() should have written a replacement
|
|
+ throw new InvalidObjectException("Deserialization is unsupported");
|
|
+ }
|
|
+
|
|
@Override
|
|
public int hashCode() {
|
|
return value.hashCode();
|
|
diff --git a/gson/src/main/java/com/google/gson/internal/LinkedHashTreeMap.java b/gson/src/main/java/com/google/gson/internal/LinkedHashTreeMap.java
|
|
index b2707c5..0cade0d 100644
|
|
--- a/gson/src/main/java/com/google/gson/internal/LinkedHashTreeMap.java
|
|
+++ b/gson/src/main/java/com/google/gson/internal/LinkedHashTreeMap.java
|
|
@@ -17,6 +17,9 @@
|
|
|
|
package com.google.gson.internal;
|
|
|
|
+import java.io.IOException;
|
|
+import java.io.InvalidObjectException;
|
|
+import java.io.ObjectInputStream;
|
|
import java.io.ObjectStreamException;
|
|
import java.io.Serializable;
|
|
import java.util.AbstractMap;
|
|
@@ -861,4 +864,9 @@ public final class LinkedHashTreeMap<K, V> extends AbstractMap<K, V> implements
|
|
private Object writeReplace() throws ObjectStreamException {
|
|
return new LinkedHashMap<K, V>(this);
|
|
}
|
|
+
|
|
+ private void readObject(ObjectInputStream in) throws IOException {
|
|
+ // Don't permit directly deserializing this class; writeReplace() should have written a replacement
|
|
+ throw new InvalidObjectException("Deserialization is unsupported");
|
|
+ }
|
|
}
|
|
diff --git a/gson/src/main/java/com/google/gson/internal/LinkedTreeMap.java b/gson/src/main/java/com/google/gson/internal/LinkedTreeMap.java
|
|
index 8046274..aaa8ce0 100644
|
|
--- a/gson/src/main/java/com/google/gson/internal/LinkedTreeMap.java
|
|
+++ b/gson/src/main/java/com/google/gson/internal/LinkedTreeMap.java
|
|
@@ -17,6 +17,9 @@
|
|
|
|
package com.google.gson.internal;
|
|
|
|
+import java.io.IOException;
|
|
+import java.io.InvalidObjectException;
|
|
+import java.io.ObjectInputStream;
|
|
import java.io.ObjectStreamException;
|
|
import java.io.Serializable;
|
|
import java.util.AbstractMap;
|
|
@@ -627,4 +630,9 @@ public final class LinkedTreeMap<K, V> extends AbstractMap<K, V> implements Seri
|
|
private Object writeReplace() throws ObjectStreamException {
|
|
return new LinkedHashMap<K, V>(this);
|
|
}
|
|
+
|
|
+ private void readObject(ObjectInputStream in) throws IOException {
|
|
+ // Don't permit directly deserializing this class; writeReplace() should have written a replacement
|
|
+ throw new InvalidObjectException("Deserialization is unsupported");
|
|
+ }
|
|
}
|
|
diff --git a/gson/src/test/java/com/google/gson/internal/LazilyParsedNumberTest.java b/gson/src/test/java/com/google/gson/internal/LazilyParsedNumberTest.java
|
|
index f108fa0..75e77bb 100644
|
|
--- a/gson/src/test/java/com/google/gson/internal/LazilyParsedNumberTest.java
|
|
+++ b/gson/src/test/java/com/google/gson/internal/LazilyParsedNumberTest.java
|
|
@@ -15,6 +15,13 @@
|
|
*/
|
|
package com.google.gson.internal;
|
|
|
|
+import java.io.ByteArrayInputStream;
|
|
+import java.io.ByteArrayOutputStream;
|
|
+import java.io.IOException;
|
|
+import java.io.ObjectInputStream;
|
|
+import java.io.ObjectOutputStream;
|
|
+import java.math.BigDecimal;
|
|
+
|
|
import junit.framework.TestCase;
|
|
|
|
public class LazilyParsedNumberTest extends TestCase {
|
|
@@ -29,4 +36,15 @@ public class LazilyParsedNumberTest extends TestCase {
|
|
LazilyParsedNumber n1Another = new LazilyParsedNumber("1");
|
|
assertTrue(n1.equals(n1Another));
|
|
}
|
|
+
|
|
+ public void testJavaSerialization() throws IOException, ClassNotFoundException {
|
|
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
+ ObjectOutputStream objOut = new ObjectOutputStream(out);
|
|
+ objOut.writeObject(new LazilyParsedNumber("123"));
|
|
+ objOut.close();
|
|
+
|
|
+ ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
|
|
+ Number deserialized = (Number) objIn.readObject();
|
|
+ assertEquals(new BigDecimal("123"), deserialized);
|
|
+ }
|
|
}
|
|
diff --git a/gson/src/test/java/com/google/gson/internal/LinkedHashTreeMapTest.java b/gson/src/test/java/com/google/gson/internal/LinkedHashTreeMapTest.java
|
|
index 2aeeeb7..77fe518 100644
|
|
--- a/gson/src/test/java/com/google/gson/internal/LinkedHashTreeMapTest.java
|
|
+++ b/gson/src/test/java/com/google/gson/internal/LinkedHashTreeMapTest.java
|
|
@@ -20,8 +20,15 @@ import com.google.gson.common.MoreAsserts;
|
|
import com.google.gson.internal.LinkedHashTreeMap.AvlBuilder;
|
|
import com.google.gson.internal.LinkedHashTreeMap.AvlIterator;
|
|
import com.google.gson.internal.LinkedHashTreeMap.Node;
|
|
+
|
|
+import java.io.ByteArrayInputStream;
|
|
+import java.io.ByteArrayOutputStream;
|
|
+import java.io.IOException;
|
|
+import java.io.ObjectInputStream;
|
|
+import java.io.ObjectOutputStream;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
+import java.util.Collections;
|
|
import java.util.Iterator;
|
|
import java.util.Map;
|
|
import java.util.Random;
|
|
@@ -224,6 +231,20 @@ public final class LinkedHashTreeMapTest extends TestCase {
|
|
}
|
|
}
|
|
|
|
+ public void testJavaSerialization() throws IOException, ClassNotFoundException {
|
|
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
+ ObjectOutputStream objOut = new ObjectOutputStream(out);
|
|
+ Map<String, Integer> map = new LinkedHashTreeMap<String, Integer>();
|
|
+ map.put("a", 1);
|
|
+ objOut.writeObject(map);
|
|
+ objOut.close();
|
|
+
|
|
+ ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
|
|
+ @SuppressWarnings("unchecked")
|
|
+ Map<String, Integer> deserialized = (Map<String, Integer>) objIn.readObject();
|
|
+ assertEquals(Collections.singletonMap("a", 1), deserialized);
|
|
+ }
|
|
+
|
|
private static final Node<String, String> head = new Node<String, String>();
|
|
|
|
private Node<String, String> node(String value) {
|
|
diff --git a/gson/src/test/java/com/google/gson/internal/LinkedTreeMapTest.java b/gson/src/test/java/com/google/gson/internal/LinkedTreeMapTest.java
|
|
index 580d25a..d9a1191 100644
|
|
--- a/gson/src/test/java/com/google/gson/internal/LinkedTreeMapTest.java
|
|
+++ b/gson/src/test/java/com/google/gson/internal/LinkedTreeMapTest.java
|
|
@@ -16,8 +16,14 @@
|
|
|
|
package com.google.gson.internal;
|
|
|
|
+import java.io.ByteArrayInputStream;
|
|
+import java.io.ByteArrayOutputStream;
|
|
+import java.io.IOException;
|
|
+import java.io.ObjectInputStream;
|
|
+import java.io.ObjectOutputStream;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
+import java.util.Collections;
|
|
import java.util.Iterator;
|
|
import java.util.Map;
|
|
import java.util.Random;
|
|
@@ -140,6 +146,20 @@ public final class LinkedTreeMapTest extends TestCase {
|
|
MoreAsserts.assertEqualsAndHashCode(map1, map2);
|
|
}
|
|
|
|
+ public void testJavaSerialization() throws IOException, ClassNotFoundException {
|
|
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
+ ObjectOutputStream objOut = new ObjectOutputStream(out);
|
|
+ Map<String, Integer> map = new LinkedTreeMap<String, Integer>();
|
|
+ map.put("a", 1);
|
|
+ objOut.writeObject(map);
|
|
+ objOut.close();
|
|
+
|
|
+ ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
|
|
+ @SuppressWarnings("unchecked")
|
|
+ Map<String, Integer> deserialized = (Map<String, Integer>) objIn.readObject();
|
|
+ assertEquals(Collections.singletonMap("a", 1), deserialized);
|
|
+ }
|
|
+
|
|
private <T> void assertIterationOrder(Iterable<T> actual, T... expected) {
|
|
ArrayList<T> actualList = new ArrayList<T>();
|
|
for (T t : actual) {
|
|
--
|
|
2.30.0
|
|
|