Skip to content

Commit d75a6ea

Browse files
committed
Fix vulnerability with whitelist-aware ObjectInputStream
Only a few specific classes are now allowed.
1 parent 235fb92 commit d75a6ea

2 files changed

Lines changed: 61 additions & 2 deletions

File tree

app/src/main/java/org/schabi/newpipe/settings/export/ImportExportManager.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import org.schabi.newpipe.streams.io.SharpOutputStream
88
import org.schabi.newpipe.streams.io.StoredFileHelper
99
import org.schabi.newpipe.util.ZipHelper
1010
import java.io.IOException
11-
import java.io.ObjectInputStream
1211
import java.io.ObjectOutputStream
1312
import java.util.zip.ZipOutputStream
1413

@@ -78,7 +77,9 @@ class ImportExportManager(private val fileLocator: NewPipeFileLocator) {
7877
try {
7978
val preferenceEditor = preferences.edit()
8079

81-
ObjectInputStream(fileLocator.settings.inputStream()).use { input ->
80+
PreferencesObjectInputStream(
81+
fileLocator.settings.inputStream()
82+
).use { input ->
8283
preferenceEditor.clear()
8384
@Suppress("UNCHECKED_CAST")
8485
val entries = input.readObject() as Map<String, *>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package org.schabi.newpipe.settings.export;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import java.io.ObjectInputStream;
6+
import java.io.ObjectStreamClass;
7+
import java.util.Set;
8+
9+
/**
10+
* An {@link ObjectInputStream} that only allows preferences-related types to be deserialized, to
11+
* prevent injections. The only allowed types are: all primitive types, all boxed primitive types,
12+
* null, strings. HashMap, HashSet and arrays of previously defined types are also allowed. Sources:
13+
* <a href="https://wiki.sei.cmu.edu/confluence/display/java/SER00-J.+Enable+serialization+compatibility+during+class+evolution">
14+
* cmu.edu
15+
* </a>,
16+
* <a href="https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#harden-your-own-javaioobjectinputstream">
17+
* OWASP cheatsheet
18+
* </a>,
19+
* <a href="https://commons.apache.org/proper/commons-io/apidocs/src-html/org/apache/commons/io/serialization/ValidatingObjectInputStream.html#line-118">
20+
* Apache's {@code ValidatingObjectInputStream}
21+
* </a>
22+
*/
23+
public class PreferencesObjectInputStream extends ObjectInputStream {
24+
25+
/**
26+
* Primitive types, strings and other built-in types do not pass through resolveClass() but
27+
* instead have a custom encoding; see
28+
* <a href="https://docs.oracle.com/javase/6/docs/platform/serialization/spec/protocol.html#10152">
29+
* official docs</a>.
30+
*/
31+
private static final Set<String> CLASS_WHITELIST = Set.of(
32+
"java.lang.Boolean",
33+
"java.lang.Byte",
34+
"java.lang.Character",
35+
"java.lang.Short",
36+
"java.lang.Integer",
37+
"java.lang.Long",
38+
"java.lang.Float",
39+
"java.lang.Double",
40+
"java.lang.Void",
41+
"java.util.HashMap",
42+
"java.util.HashSet"
43+
);
44+
45+
public PreferencesObjectInputStream(final InputStream in) throws IOException {
46+
super(in);
47+
}
48+
49+
@Override
50+
protected Class<?> resolveClass(final ObjectStreamClass desc)
51+
throws ClassNotFoundException, IOException {
52+
if (CLASS_WHITELIST.contains(desc.getName())) {
53+
return super.resolveClass(desc);
54+
} else {
55+
throw new ClassNotFoundException("Class not allowed: " + desc.getName());
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)