diff --git a/core/src/main/java/com/threerings/io/ObjectInputStream.java b/core/src/main/java/com/threerings/io/ObjectInputStream.java index c5887c48a..3f03535cf 100644 --- a/core/src/main/java/com/threerings/io/ObjectInputStream.java +++ b/core/src/main/java/com/threerings/io/ObjectInputStream.java @@ -278,35 +278,42 @@ public class ObjectInputStream extends DataInputStream protected void validateClassPrefix (short code, String cname) throws IOException { - for (int start = 0, end = cname.length(); start < end; ++start) { - char c = cname.charAt(start); - if (c == '[') continue; // continue the loop to step past array markers - - // if it's a single character do a quick check: - if (start == end - 1) { - switch (c) { + if (cname.charAt(0) == '[') { + // array handling. It's ok to throw if the cname is in an invalid format... + for (int start = 1, last = cname.length() - 1; true; ++start) { + switch (cname.charAt(start)) { + case '[': continue; // advance `start` case 'I': case 'Z': case 'B': case 'S': case 'C': case 'J': case 'F': case 'D': - return; // valid - } - } else { - // 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 + if (start == last) return; // valid + break; + + case 'L': + if (cname.charAt(last) == ';' && + isValidClassPrefix(cname.substring(start + 1, last))) return; // valid + break; } + break; // once we see any non-[ character, we're done } - break; // if we didn't see a [, we're done processing - } + + } else if (isValidClassPrefix(cname)) return; log.warning("Blocked deserialization of non-whitelisted class", "code", code, "class", 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 * ObjectOutputStream#writeBareObject(Object)}.