Class check cleanup

This commit is contained in:
fourbites
2026-03-20 20:53:26 +01:00
parent 1fd6240d09
commit 84bed9e479
@@ -246,32 +246,8 @@ public class ObjectInputStream extends DataInputStream
protected ClassMapping createClassMapping (short code, String cname) protected ClassMapping createClassMapping (short code, String cname)
throws IOException, ClassNotFoundException throws IOException, ClassNotFoundException
{ {
// validate the class name against the whitelist before loading
if (_allowedPrefixes != null) { if (_allowedPrefixes != null) {
// strip array encoding to get the component class name validateClassPrefix(code, cname);
// e.g. "[Lcom.threerings.Foo;" -> "com.threerings.Foo"
String checkName = cname;
while (checkName.startsWith("[")) {
checkName = checkName.substring(1);
}
if (checkName.startsWith("L") && checkName.endsWith(";")) {
checkName = checkName.substring(1, checkName.length() - 1);
}
// primitive array descriptors (I, Z, B, S, C, J, F, D) are always safe
boolean allowed = (checkName.length() == 1);
for (String prefix : _allowedPrefixes) {
if (checkName.startsWith(prefix)) {
allowed = true;
break;
}
}
if (!allowed) {
log.warning("Blocked deserialization of non-whitelisted class",
"code", code, "class", cname);
throw new IOException(
"Deserialization of class not allowed: " + cname);
}
} }
// resolve the class and streamer // resolve the class and streamer
@@ -293,6 +269,40 @@ public class ObjectInputStream extends DataInputStream
return new ClassMapping(code, sclass, streamer); return new ClassMapping(code, sclass, streamer);
} }
/**
* Validates that a class name is allowed by the configured prefix whitelist. Array prefixes
* ({@code [}) are stripped first. Primitive type descriptors ({@code I}, {@code Z}, etc.) are
* always allowed. Object type descriptors ({@code Lcom.threerings.Foo;}) are checked against
* the whitelist.
*/
protected void validateClassPrefix (short code, String cname)
throws IOException
{
// strip array prefixes to get the component type descriptor
int start = 0;
while (start < cname.length() && cname.charAt(start) == '[') {
start++;
}
String desc = cname.substring(start);
// primitive descriptors (I, Z, B, S, C, J, F, D) are always safe
if (!desc.startsWith("L") || !desc.endsWith(";")) {
return;
}
// extract the class name from "Lcom.threerings.Foo;"
String className = desc.substring(1, desc.length() - 1);
for (String prefix : _allowedPrefixes) {
if (className.startsWith(prefix)) {
return;
}
}
log.warning("Blocked deserialization of non-whitelisted class",
"code", code, "class", cname);
throw new IOException("Deserialization of class not allowed: " + cname);
}
/** /**
* Reads an object from the input stream that was previously written with {@link * Reads an object from the input stream that was previously written with {@link
* ObjectOutputStream#writeBareObject(Object)}. * ObjectOutputStream#writeBareObject(Object)}.