Skip to content

8365203: defineClass with direct buffer can cause use-after-free #26724

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

minborg
Copy link
Contributor

@minborg minborg commented Aug 11, 2025

Description

This PR proposes to update the ClassLoader implementation to properly guard access to the provided ByteBuffer when defining a class using defineClass(String, ByteBuffer, ...). Specifically, calls to SharedSecrets.getJavaNioAccess().acquireSession(ByteBuffer) and releaseSession(ByteBuffer) have been introduced to ensure safe and consistent buffer access throughout the native class definition process, even in the case of a ByteBuffer is backed by a MemorySegment.

Impact

This modification is internal to the ClassLoader implementation and does not affect the public API.
Improves the robustness and security of class loading from buffers.

Testing

Tier 1, 2, and 3 JDK tests pass on multiple platforms.


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Issue

  • JDK-8365203: defineClass with direct buffer can cause use-after-free (Bug - P4)

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/26724/head:pull/26724
$ git checkout pull/26724

Update a local copy of the PR:
$ git checkout pull/26724
$ git pull https://git.openjdk.org/jdk.git pull/26724/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 26724

View PR using the GUI difftool:
$ git pr show -t 26724

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/26724.diff

Using Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Aug 11, 2025

👋 Welcome back pminborg! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Aug 11, 2025

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

@openjdk
Copy link

openjdk bot commented Aug 11, 2025

@minborg The following label will be automatically applied to this pull request:

  • core-libs

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

final class GuardByteBuffer {

@Test
void guardCrash() throws InterruptedException {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was not able to reproduce the crash using this test on a Mac. The original reproducer worked on a Windows machine.

postDefineClass(c, protectionDomain);
return c;

SharedSecrets.getJavaNioAccess().acquireSession(b);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that the fields in SharedSecrets are @Stable, we do not have to make a local copy in a static final field.

@minborg minborg marked this pull request as ready for review August 11, 2025 12:37
@openjdk openjdk bot added the rfr Pull request is ready for review label Aug 11, 2025
@mlbridge
Copy link

mlbridge bot commented Aug 11, 2025

Webrevs

SharedSecrets.getJavaNioAccess().acquireSession(b);
try {
Class<?> c = defineClass2(this, name, b, b.position(), len, protectionDomain, source);
postDefineClass(c, protectionDomain);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we leave postDefineClass out of this acquire-release scope? I don't see any reason including this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it matters here because something looking to close the arena around the time that it wants to defineClass with memory allocated from that arena is broken.

}
};
final List<Thread> threads = new ArrayList<>();
for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means all cores spinning for 20s - we'll have to see if it causes any side effects and slow down of other tests that happen to run at the same time in other agent VMs (make run-test uses concurrency by default).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, tier 1 tests are recommended to run for 10 seconds.

@AlanBateman
Copy link
Contributor

The change looks okay. One thing to check if whether we have tests for JNI GetDirectBufferAddress when the byte buffer is a view of a memory segment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core-libs [email protected] rfr Pull request is ready for review
Development

Successfully merging this pull request may close these issues.

3 participants