Type-check the exemplar in the EnumMap server field serializer - #10392
Open
Nexory wants to merge 2 commits into
Open
Type-check the exemplar in the EnumMap server field serializer#10392Nexory wants to merge 2 commits into
Nexory wants to merge 2 commits into
Conversation
EnumMap_ServerCustomFieldSerializer overrode the type-checking server instantiateInstance but discarded the type information and called the untyped client instantiate, which reads the exemplar with a bare readObject(). Every other collection serializer reads what it instantiates from through the typed path; TreeMap and TreeSet are the direct precedent. Because the exemplar was read untyped, a request could substitute a non-enum type for it, and new EnumMap(nonEnumClass) throws an uncaught NullPointerException instead of a clean serialization error. Add a server-side instantiate that reads the exemplar with readObject(Enum.class, resolvedTypes), so a non-enum is rejected with SerializedTypeViolationException like the other serializers. A valid enum constant still passes and getClass() is unchanged, so behaviour for valid EnumMaps is identical.
The type-check test family covers every collection serializer for exemplar and element substitution except EnumMap. Add testEnumMapSpoofingClass, its request generator, and an EnumMap method on the existing ClassesParamTestClass service. Before the serializer change the test fails with an uncaught NullPointerException; after it, the request is rejected with IncompatibleRemoteServiceException wrapping SerializedTypeViolationException, matching the other spoofing tests. RPCTypeCheckTest passes with 26 tests.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #10391.
EnumMap_ServerCustomFieldSerializeroverrode the type-checking serverinstantiateInstancebut threw the type information away and called theuntyped client
instantiate, which reads the exemplar with a barereadObject(). Every other collection serializer reads what it instantiatesfrom through the typed path;
TreeMap/TreeSetare the direct precedent(
readObject(Comparator.class, resolvedTypes)).Because the exemplar was read untyped, a request could substitute a non-enum
type for it, and
new EnumMap(nonEnumClass)throws an uncaughtNullPointerException(keyUniverse is null) instead of a clean serializationerror.
This adds a server-side
instantiate(streamReader, expectedParameterTypes, resolvedTypes)that reads the exemplar withreadObject(Enum.class, resolvedTypes), so a non-enum is rejected withSerializedTypeViolationExceptionthe same way the other serializers reject mismatched types. A legitimate enum
constant still passes, and the resulting
getClass()is unchanged from before,so behaviour for valid EnumMaps is identical.
Test
RPCTypeCheckTest.testEnumMapSpoofingClassbuilds an EnumMap RPC message whoseexemplar is an
Integerand runs it throughRPC.decodeRequest. Before thischange it fails with an uncaught
NullPointerException; after it, the requestis rejected with
IncompatibleRemoteServiceExceptionwrappingSerializedTypeViolationException, matching the existing spoofing tests for theother collections. The full
RPCTypeCheckTestpasses (26 tests).Diff
EnumMap_ServerCustomFieldSerializer.java(+16/-1): the typed instantiate.RPCTypeCheckTest.java(+39): the test, its request generator, and anEnumMapmethod on the existingClassesParamTestClasstest service.RPCTypeCheckFactory.java(+11): a helper to write an EnumMap message with asubstituted exemplar.
Note
I confirmed the failing input is reachable through the normal servlet path: an
embedded
RemoteServiceServletwith anEnumMapparameter and a strictserialization policy (only the service's own types allow-listed) returns HTTP
500 on the crafted request before this change and handles it cleanly after. I
can share that harness if useful. Happy to adjust the approach; using
Enum.classas the expected type is the least invasive floor, but reading theexemplar against
expectedParameterTypes[0]when present would be stricter ifyou prefer.