Only check for the "L" and ";" if we're in an array.

I can't help but over-optimize. We're parsing the result of class.getName(),
it will be a bare class name if not in the array.

Also: Stop going out of our way to not throw an exception if the input
is malformed, as that's the desired result for bad input.
This commit is contained in:
Ray J. Greenwell
2026-03-21 14:46:35 -07:00
parent 5e17d3ba67
commit d7b4e10430
@@ -278,35 +278,42 @@ public class ObjectInputStream extends DataInputStream
protected void validateClassPrefix (short code, String cname) protected void validateClassPrefix (short code, String cname)
throws IOException throws IOException
{ {
for (int start = 0, end = cname.length(); start < end; ++start) { if (cname.charAt(0) == '[') {
char c = cname.charAt(start); // array handling. It's ok to throw if the cname is in an invalid format...
if (c == '[') continue; // continue the loop to step past array markers for (int start = 1, last = cname.length() - 1; true; ++start) {
switch (cname.charAt(start)) {
// if it's a single character do a quick check: case '[': continue; // advance `start`
if (start == end - 1) {
switch (c) {
case 'I': case 'Z': case 'B': case 'S': case 'C': case 'J': case 'F': case 'D': case 'I': case 'Z': case 'B': case 'S': case 'C': case 'J': case 'F': case 'D':
return; // valid if (start == last) return; // valid
break;
case 'L':
if (cname.charAt(last) == ';' &&
isValidClassPrefix(cname.substring(start + 1, last))) return; // valid
break;
} }
} else { break; // once we see any non-[ character, we're done
// This is annoying: Something else is pre-stripping the L if not in an array?
if (c == 'L' && cname.endsWith(";")) {
++start;
--end;
}
String className = cname.substring(start, end);
for (String prefix : _allowedPrefixes) {
if (className.startsWith(prefix)) return; // valid
}
}
break; // if we didn't see a [, we're done processing
} }
} else if (isValidClassPrefix(cname)) return;
log.warning("Blocked deserialization of non-whitelisted class", log.warning("Blocked deserialization of non-whitelisted class",
"code", code, "class", cname); "code", code, "class", cname);
throw new IOException("Deserialization of class not allowed: " + cname); throw new IOException("Deserialization of class not allowed: " + cname);
} }
/**
* Validate a class name against the prefix whitelist, after array information has been
* removed and primitive arrays handled elsewhere.
*/
protected boolean isValidClassPrefix (String className)
{
for (String prefix : _allowedPrefixes) {
if (className.startsWith(prefix)) return true;
}
return false;
}
/** /**
* 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)}.