Skip to content
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

6714834: JarFile.getManifest() leaves an open InputStream as an undocumented side effect #186

Closed
wants to merge 2 commits into from

Conversation

jaikiran
Copy link
Member

@jaikiran jaikiran commented Sep 15, 2020

Can I please get a review and a sponsor for this patch which fixes the issue reported in https://bugs.openjdk.java.net/browse/JDK-6714834?

As noted by the reporter in that issue, when the java.util.jar.JarFile.getManifest() method is called, it internally calls the private getManifestFromReference. This private method implementation opens an InputStream for passing it on to the constructor of the Manifest, but never closes it. The commit here fixes that part to use a try-with-resources to close the InputStream once the Manifest instance is created.

This issue is only applicable when the JarFile is created with verify as false, which isn't the default.

In that issue report, there's also a mention that this can lead to incorrect manifest files ending up in jar files:

can lead to serious and hard to track bugs (e.g. when replacing the manifest and generating a new JarFile, the old one can be unexpectedly taken in some circumstances unless one calls myJar.close() after myJar.getManifest())

I have gone through the code to see how this can happen and have also done some testing to see if this is possible. But my tests and the code haven't shown this as a possibilty. The Manifest doesn't store any InputStream once it's created nor does the JarFile store that stream. Although the ZipFile, which JarFile extends from, does store these opened InputStreams into a Set, it only does it to close them as part of the java.lang.ref.Cleaner contract and from what I can see, none of these APIs return or use these stored InputStreams for any other purpose. So I don't see how a leaking InputStream can lead to a wrong Manifest ending up in a copy of a JarFile. So the commit in this PR only addresses the leaking InputStream.

I haven't added any new tests to verify this fix because given the nature of this issue, I couldn't think of a consistent and determinstic way to verify it. I have however run the jdk:tier1 tests locally which hasn't shown any related failures.


Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change must be properly reviewed

Issue

  • JDK-6714834: JarFile.getManifest() leaves an open InputStream as an undocumented side effect

Reviewers

Download

$ git fetch https://git.openjdk.java.net/jdk pull/186/head:pull/186
$ git checkout pull/186

@bridgekeeper
Copy link

bridgekeeper bot commented Sep 15, 2020

👋 Welcome back jpai! 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 openjdk bot added the rfr Pull request is ready for review label Sep 15, 2020
@openjdk
Copy link

openjdk bot commented Sep 15, 2020

@jaikiran The following labels will be automatically applied to this pull request: core-libs security.

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

@openjdk openjdk bot added security security-dev@openjdk.org core-libs core-libs-dev@openjdk.org labels Sep 15, 2020
@mlbridge
Copy link

mlbridge bot commented Sep 15, 2020

Webrevs

man = new Manifest(super.getInputStream(manEntry), getName());
try (final InputStream is = super.getInputStream(manEntry)) {
man = new Manifest(is, getName());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

There is a cleaner so shouldn't have a leak, even if the JarFile is not explicitly closed.
The noisy "final" can be dropped, otherwise looks good.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thank you for the review Alan. I've updated this PR to remove the final. And yes as you note, this doesn't really leak. This change closes the InputStream earlier, as soon as it is done, instead of waiting for the Cleaner to kick in.

Copy link
Member

@dfuch dfuch left a comment

Choose a reason for hiding this comment

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

Hi Jaikiran,

This is not an area I know too well - so I won't review formally, but the proposed changes look reasonable to me. Closing the stream from within JarFile after creating the manifest looks innocuous and should release any resource held by the stream earlier instead of waiting for the JarFile to be closed. As long as the input stream close() method is idem potent this should be safe, and AFAICS that is the case for the two input stream subclasses that can be returned by ZipFile::getInputStream.

WRT to the claims in the JBS issue I see that that was logged against Java 6: there was no Cleanable at this time and it is possible that the internals of ZipFile/JarFile were quite different.

@jaikiran
Copy link
Member Author

Thank you for the review Daniel.

WRT to the claims in the JBS issue I see that that was logged against Java 6: there was no Cleanable at this time and it is possible that the internals of ZipFile/JarFile were quite different.

You are right. I hadn't paid attention to that detail. It's likely that it might have been behaving differently at that time.

As for this:

As long as the input stream close() method is idem potent this should be safe, and AFAICS that is the case for the two input stream subclasses that can be returned by ZipFile::getInputStream.

I'm curious, in the context of this change, why idempotency would be a necessity. Would there be a "double close" somehow on this InputStream instance?

@dfuch
Copy link
Member

dfuch commented Sep 15, 2020

I'm curious, in the context of this change, why idempotency would be a necessity. Would there be a "double close" somehow on this InputStream instance?

My bad - I hadn't realised closing the input stream would also remove it from the Cleanable resource set, so I thought it might be closed again when the jar file is closed.

@jaikiran
Copy link
Member Author

As for this:

As long as the input stream close() method is idem potent this should be safe, and AFAICS that is the case for the two input stream subclasses that can be returned by ZipFile::getInputStream.

I'm curious, in the context of this change, why idempotency would be a necessity. Would there be a "double close" somehow on this InputStream instance?

I think I understand what you meant. You were perhaps talking about the JarFile.close triggering the Cleanable to close this InputStream in addition to the try-with-resources already calling close on that stream. Like you rightly note, the implementation of those streams already handles that aspect correctly.

Copy link
Contributor

@LanceAndersen LanceAndersen left a comment

Choose a reason for hiding this comment

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

I am fine with this as well. I will pull over the change and just sanity check it via mach5 and then will sponsor

@openjdk
Copy link

openjdk bot commented Sep 15, 2020

@jaikiran This change now passes all automated pre-integration checks. In addition to the automated checks, the change must also fulfill all project specific requirements

After integration, the commit message will be:

6714834: JarFile.getManifest() leaves an open InputStream as an undocumented side effect

Reviewed-by: lancea, alanb
  • If you would like to add a summary, use the /summary command.
  • To credit additional contributors, use the /contributor command.
  • To add additional solved issues, use the /issue command.

Since the source branch of this PR was last updated there have been 24 commits pushed to the master branch:

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid automatic rebasing, please merge master into your branch, and then specify the current head hash when integrating, like this: /integrate e5866aa7560e1a6077a90a5902ec61de76922440.

As you do not have Committer status in this projectan existing Committer must agree to sponsor your change. Possible candidates are the reviewers of this PR (@dfuch, @LanceAndersen, @AlanBateman) but any other Committer may sponsor as well.

➡️ To flag this PR as ready for integration with the above commit message, type /integrate in a new comment. (Afterwards, your sponsor types /sponsor in a new comment to perform the integration).

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Sep 15, 2020
@LanceAndersen
Copy link
Contributor

/sponsor

@openjdk
Copy link

openjdk bot commented Sep 15, 2020

@LanceAndersen The change author (@jaikiran) must issue an integrate command before the integration can be sponsored.

@LanceAndersen
Copy link
Contributor

@jaikiran Please go ahead and integrate this and I can then sponsor (has to be done in that order)

@jaikiran
Copy link
Member Author

/integrate

@openjdk openjdk bot added the sponsor Pull request is ready to be sponsored label Sep 16, 2020
@openjdk
Copy link

openjdk bot commented Sep 16, 2020

@jaikiran
Your change (at version 11fa077) is now ready to be sponsored by a Committer.

@LanceAndersen
Copy link
Contributor

/sponsor

@openjdk openjdk bot closed this Sep 16, 2020
@openjdk openjdk bot added integrated Pull request has been integrated and removed sponsor Pull request is ready to be sponsored ready Pull request is ready to be integrated rfr Pull request is ready for review labels Sep 16, 2020
@openjdk
Copy link

openjdk bot commented Sep 16, 2020

@LanceAndersen @jaikiran Since your change was applied there have been 24 commits pushed to the master branch:

Your commit was automatically rebased without conflicts.

Pushed as commit 671dfba.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

@jaikiran jaikiran deleted the 6714834 branch September 16, 2020 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core-libs core-libs-dev@openjdk.org integrated Pull request has been integrated security security-dev@openjdk.org
Development

Successfully merging this pull request may close these issues.

4 participants