Skip to content

fix: don't resolve a wire-supplied manifest class the serializer will not use - #3495

Open
pjfanning wants to merge 1 commit into
apache:mainfrom
pjfanning:wire-manifest-class-loading
Open

fix: don't resolve a wire-supplied manifest class the serializer will not use#3495
pjfanning wants to merge 1 commit into
apache:mainfrom
pjfanning:wire-manifest-class-loading

Conversation

@pjfanning

Copy link
Copy Markdown
Member

Motivation

Serialization.deserializeByteArray resolves the manifest string carried on the wire into a Class via dynamicAccess.getClassFor for every plain Serializer with a non-empty manifest — without checking whether that serializer actually wants a type hint.

Serializers.manifestFor is the sending side:

case _ => if (s.includeManifest) message.getClass.getName else ""

So a conforming peer never sends a manifest to a serializer declaring includeManifest = false. When one arrives anyway it can only have come from a non-conforming or hostile sender — and the class that gets loaded is then handed to a serializer that ignores it.

ByteArraySerializer and NullSerializer both declare includeManifest = false and are bound by default, reachable by serializer id from the wire. A peer can therefore name any class on the classpath and have it loaded. The class is loaded with Class.forName(fqcn, false, loader) so static initializers do not run, but it still gives:

  • a classpath-probing oracle — success versus NotSerializableException fingerprints which libraries and versions are present;
  • metaspace growth that is never released, plus an entry retained forever in manifestCache, for each distinct class an attacker names.

Modification

Pass None to a plain Serializer that declares includeManifest = false, instead of resolving the wire-supplied name — exactly what a conforming sender produces for that serializer. Serializers that do ask for the hint (e.g. ProtobufSerializer) are unchanged.

One-line guard, no new configuration, no API change.

Result

A peer can no longer drive class loading through a serializer that ignores the type hint. Conforming messages behave exactly as before.

Tests

  • sbt "actor-tests/testOnly org.apache.pekko.serialization.WireManifestClassLoadingSpec" — new. The first case is directional: with the fix reverted it fails with java.io.NotSerializableException: Cannot find manifest class [com.example.NotOnTheClasspath] for serializer with id [9911], which is the wire-driven load this change removes. The other two cases pin unchanged behaviour for includeManifest = true, including that an unknown manifest class still fails.
  • sbt "actor-tests/testOnly org.apache.pekko.serialization.SerializeSpec" — existing spec passes unchanged
  • sbt "actor/mimaReportBinaryIssues" — no issues

References

Refs #3478

… not use

Motivation:
Serialization.deserializeByteArray resolved the manifest string from the wire
into a Class via dynamicAccess.getClassFor for every plain Serializer, without
checking whether that serializer wants a type hint. Serializers.manifestFor
shows a conforming peer only sends a manifest when includeManifest is true, so
for a serializer declaring includeManifest = false the class name can only have
come from a non-conforming or hostile sender - and the loaded class is then
discarded. ByteArraySerializer and NullSerializer are bound by default and
reachable by serializer id, so a peer could name any class on the classpath and
have it loaded: a classpath-probing oracle, and metaspace and manifest-cache
growth that is never released.

Modification:
Pass None to a plain Serializer that declares includeManifest = false instead of
resolving the wire-supplied name, which is exactly what a conforming sender
produces. Serializers that do ask for the hint are unchanged.

Result:
A peer can no longer drive class loading through a serializer that ignores the
type hint. No behaviour change for conforming messages.

Tests:
- sbt "actor-tests/testOnly org.apache.pekko.serialization.WireManifestClassLoadingSpec" - new; the first case fails without this change with "Cannot find manifest class [com.example.NotOnTheClasspath]"
- sbt "actor-tests/testOnly org.apache.pekko.serialization.SerializeSpec" - existing spec passes unchanged
- sbt "actor/mimaReportBinaryIssues" - no issues

References:
Refs apache#3478
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant