Repository navigation
Conversation
* Apply the outer ObjectInputFilter to nested streams Log4j's own deserialization code now takes a neutral stance: the nested streams created by `SerializationUtil.readWrappedObject` get exactly the `ObjectInputFilter` of the outer stream, nothing less and nothing more. - copy the outer filter also when the outer stream is a `FilteredObjectInputStream` - remove `DefaultObjectInputFilter`: plain `ObjectInputStream`s no longer get the Log4j allowlist added to their filter - remove `SerializationUtil.assertFiltered` and all its call sites - deprecate `FilteredObjectInputStream` and document its allowlist, its limits and the alternatives (`ObjectInputFilter`, `jdk.serialFilter`) Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> * Add PR number to changelog entries Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> * Import `FilteredObjectInputStream` in `SerializationUtil` Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> * Remove the changelog entry of #4098 The `assertFiltered` checks added by #4098 were never released and are removed by this PR. Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> * Only export `util.internal` to `log4j-core` Since `assertFiltered` is removed, `log4j-1.2-api` and the SLF4J bindings no longer use `SerializationUtil`. Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> * Improve `readWrappedObject` tests The previous test also passed before the change. The new tests check that `readWrappedObject` does not add an allowlist of its own, and that the filter of the outer stream is also applied if the outer stream is a `FilteredObjectInputStream`. Suggested by @FreeAndNil. Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit d2a8a11)
* Reject dynamic proxies in FilteredObjectInputStream Dynamic proxy class descriptors are resolved through `resolveProxyClass`, not `resolveClass`, so they bypassed the deserialization allowlist on Java 8. The JEP 290 filter used on Java 9 and later already rejects proxies, since their synthetic class names never match the allowlist; this aligns the Java 8 path by rejecting proxies outright. Part of the hardening series from #4168. Assisted-By: Claude Fable 5 <noreply@anthropic.com> * Shorten `resolveProxyClass` Javadoc Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit a8578d1)
* Apply the deserialization filter in test helpers on Java 9+ The `SerialUtil` test helper returned a plain, unfiltered `ObjectInputStream` on Java 9 and later, so the deserialization allowlist was only ever exercised by tests running on a Java 8 toolchain. It now installs `DefaultObjectInputFilter` (reflectively, since the class must still compile and run on Java 8), combined with an `ObjectInputFilter.Config.createFilter` delegate built from the caller-supplied extra allowed classes, reproducing the `FilteredObjectInputStream` semantics on modern JDKs. When `DefaultObjectInputFilter` is absent (it only exists in the packaged multi-release JAR), the helper falls back to `FilteredObjectInputStream` on any Java version. `SerializationTestHelper` in `log4j-1.2-api` now delegates to `SerialUtil`, so its `org.apache.log4j.*` extras are honored on all Java versions as well. Part of the hardening series from #4168. Assisted-By: Claude Fable 5 <noreply@anthropic.com> * Always use `FilteredObjectInputStream` in `SerialUtil` `DefaultObjectInputFilter` is being removed (#4365). Using `FilteredObjectInputStream` on every Java version checks that the serialized forms of Log4j stay within its documented allowlist. Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> * Test log event deserialization with `jdk.serialFilter` Adds a Surefire execution to `log4j-core-test` that runs the log event serialization tests with the process-wide `jdk.serialFilter` recommended by OpenJDK, and notes in `SerialUtil` that using `FilteredObjectInputStream` in tests is not a recommendation. Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> * Select serialization tests by tag - tag the tests that deserialize Log4j classes with `serialization` and select them by tag in the `test-serial-filter` execution - migrate `SerializedLayoutTest` to JUnit 5 - make `SerialUtil` return a plain `ObjectInputStream` if `jdk.serialFilter` is set, and document the two kinds of tests it is used for Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 5b89c4d)
* Serialize the LogEvent message delegate through the filtered wrapper `Log4jLogEvent.LogEventProxy` used `java.rmi.MarshalledObject` to transport its `Message` delegate. `MarshalledObject.get()` deserializes its embedded bytes on a private, unfiltered `ObjectInputStream`, so the delegate escaped the deserialization allow-list entirely. The message is now written with the same `SerializationUtil.writeWrappedObject`/`readWrappedObject` mechanism used by `ObjectMessage`, which re-applies the allow-list to the nested stream, and `java.rmi.MarshalledObject` is removed from the allow-list. Compatibility: log events serialized by Log4j 2.8.2-2.25.x are rejected by newer readers, since `MarshalledObject` no longer passes the filter. Events serialized by this version remain readable by older versions, with the message downgraded to a `SimpleMessage`. The serialized-event fixture in `Log4jLogEventTest` is regenerated accordingly, and the stale, unused `serializedEvent.dat` resource is removed (`SerializedLayoutTest` always rewrites it before reading). Part of the hardening series from #4168. Assisted-By: Claude Fable 5 <noreply@anthropic.com> * Remove `MarshalledObject` from the documented allowlist and test filter Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> * Fall back to a serializable value for unserializable objects `SerializationUtil.writeWrappedObject` now takes a fallback, which is written instead of the object if it is not `Serializable` or its serialization fails. Failed serializations are logged as warnings. - `LogEventProxy` writes a `SimpleMessage` with the formatted message, as it did when the message was wrapped in a `MarshalledObject`. - `ObjectMessage` writes its formatted message. - `ParameterizedMessage` and `SortedArrayStringMap` write the string representation of the value. For `SortedArrayStringMap`, this replaces the `null` previously written for non-serializable values. `UnserializableMessage` in `log4j-api-test` provides a reusable example of a `Serializable` object that cannot be serialized. Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> * Note the serialization format change in the changelog Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> * Throw on nested objects rejected during deserialization `readWrappedObject` returned `null` for any nested object that could not be read, including classes rejected by the filter of the stream. The nested stream now behaves like the outer one: `IOException`s, including filter rejections, are thrown. Only classes that are not available on the reader, `ClassNotFoundException` and `LinkageError`, are still replaced with `null`. Adds tests with a nested `java.net.URI`, which is not on the allowlist, in `ObjectMessage` and in a `Log4jLogEvent`. Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> * Test deserialization of a message with an unknown class A message whose class is allowed by the deserialization filter, but not available to the reader, degrades to a `SimpleMessage` with the formatted message. The Base64 fixtures in `Log4jLogEventTest` are folded into multiple lines. Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 9cb17cf)
Use the default Java serialization for all the fields of `SortedArrayStringMap`, except `values`, which is written as a `byte[][]` array. Each value is serialized separately, so that values that cannot be serialized are replaced with their string representation. `SerializationUtil` gets the `wrapObject` and `unwrapObject` helpers, which serialize and deserialize a single object to and from a byte array, and the `wrapObjects` and `unwrapObjects` helpers, which do the same for each element of an array. The serialized form is incompatible with previous versions, so the `serialVersionUID` is changed. Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 6bba23c)
…Message` (#4274) * Serialize message arguments with the array helpers `ObjectArrayMessage` and `ParameterizedMessage` now write their arguments as a single `byte[][]` array, built with `SerializationUtil.wrapObjects`, instead of a length followed by the wrapped arguments. Each argument is serialized separately, so that arguments that cannot be serialized are replaced with their string representation, and the arrays are allocated by the JDK. This also fixes the serialization of a `ParameterizedMessage` with `null` arguments, which threw a `NullPointerException`. The serialized forms are incompatible with previous versions, so the `serialVersionUID`s are changed. Assisted-By: Claude Opus 5.5 <noreply@anthropic.com> * Update src/changelog/.2.x.x/4274_wrap_object_array_message_serialization.xml --------- Co-authored-by: Ramanathan <ramanathan@apache.org> (cherry picked from commit 6a4d9c2)
Assisted-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
@ppkarwasz can you please check this? apache/logging-log4j-samples#436 |
| import org.apache.logging.log4j.util.StackLocatorUtil; | ||
| import org.apache.logging.log4j.util.StringMap; | ||
| import org.apache.logging.log4j.util.Strings; | ||
| import org.apache.logging.log4j.util.internal.SerializationUtil; |
Contributor
There was a problem hiding this comment.
org.apache.logging.log4j.util.internal has no package-info.java on 2.25.x, so log4j-api does not export it. The log4j-core bundle then has an Import-Package that nothing provides and does not resolve in OSGi. Can we use the WrappedObjects copy from #4385, so both patch lines match?
Contributor
|
One commit per source PR with the differences listed makes this easy to compare with |
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.
Important
This PR is part of the deserialization hardening work tracked in #4168. The Logging Services PMC does not use nor recommend Java serialization/deserialization, and our security FAQ has long documented this position. This work is submitted solely to reduce the false-positive "vulnerability" reports that keep being filed regardless of that FAQ. Its utility for end users is close to zero.
Backports the following PRs from
2.xto2.25.x, one cherry-picked commit (-x) per PR:ObjectInputFilterto nested streams #4365: Apply the outerObjectInputFilterto nested streamsFilteredObjectInputStream#4269: Reject dynamic proxies inFilteredObjectInputStreamLogEventmessage withoutMarshalledObject#4271: Serialize theLogEventmessage withoutMarshalledObjectSortedArrayStringMap#4272: Simplify the serialization ofSortedArrayStringMapObjectArrayMessageandParameterizedMessage#4274: Simplify the serialization ofObjectArrayMessageandParameterizedMessageDifferences from
2.xFilteredObjectInputStreamgets the new Javadoc from Apply the outerObjectInputFilterto nested streams #4365, but is not marked@Deprecatedon2.25.x. The correspondingdeprecatedchangelog entry is dropped.SerialUtilandSerializableMatchersoverloads,UnserializableMessage,Tags.SERIALIZATION) are annotated with@BaselineIgnore("2.25.6")instead.readObject(ObjectInputStream)method argument checks #4098 is not on2.25.x: theassertFilteredcalls removed by Apply the outerObjectInputFilterto nested streams #4365 only existed inObjectMessage,ParameterizedMessageandSortedArrayStringMap; theutil.internalpackage-info.javais not added. From the test helpers of Apply the deserialization filter in test helpers on Java 9+ #4270 only what the backported tests need was taken; inlog4j-core-test/pom.xmlonly thetest-serial-filterexecution is added.Compatibility
As on
2.x, the serialized forms ofLog4jLogEvent,SortedArrayStringMap,ObjectArrayMessageandParameterizedMessagechange, and theirserialVersionUIDs are changed: data serialized by2.25.5or earlier cannot be deserialized by this version and vice versa.Testing
./mvnw installoflog4j-api-java9,log4j-api,log4j-api-test,log4j-core-java9,log4j-core,log4j-core-testandlog4j-1.2-apion JDK 17: all tests pass (including thetest-serial-filterexecution) and the bnd baseline checks succeed.🤖 Generated with Claude Code