-
Notifications
You must be signed in to change notification settings - Fork 5.7k
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
8306561: Possible out of bounds access in print_pointer_information #16381
Conversation
👋 Welcome back TOatGithub! A progress list of the required criteria for merging this PR into |
/label add hotspot |
@TOatGithub |
Webrevs
|
@TOatGithub I changed the description in JBS since this is not AIX specific. Could you adjust the PR title please? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would fix it another way. The underlying assumption in MallocHeader::looks_valid() is that the header resides fully in readable memory. The caller must make sure of that.
The better way to fix this would be in print_pointer_information(). It must make sure, before calling MallocHeader::looks_valid(), that the header is contained fully in readable memory.
Something like:
- if (!os::is_readable_pointer(here)) {
+ if (!os::is_readable_pointer(here) || !os::is_readable_pointer(here + sizeof(MallocHeader) {
or something similar.
Agreed. Would you still prefer to blow up if the caller hands down bad pointers? In other words: should MallocHeader::looks_valid() not do my additional check? |
Yes, let it blow up then. |
Thanks for pointing this out, and kudos to @JoKern65 for his help and insights; he confirms your point. |
@tstuefe: I helped analyzing this problem by writing a plain c test pgm mmaping a page and trying to read beyound. On AIX as expected the very next byte after the requested region leads to a segmentation violation, but on linux (both flavours, linuxintel and linuxppc64) I was able to read exactly 20 KB beyond, before running into segmentation violation. |
Plain bad luck and rare test execution. Whether or not you can read over the end of an mmaped segment depends on whether there are VMAs mapped beyond that. Linux kernel clusters VMAs to keep VMA fragmentation down. So you may have adjacent mappings. This is subject to ASLR of course but I always see the VMAs pretty much clustered regardless of ASLR. And though this sounds like it should be random, you can have a pretty consistent order of VMA allocation across many VM runs, and therefore similarly looking process memory maps. Just looking at /proc/pid/maps will be probably clearer to you than me explaining it :) |
Just read your answer and I see you wrote a little test program that shows that behavior, probably single threaded. The same explanation applies here though, unless there is a simple bug. For instance, if - after the mmap - you do something that allocates C-heap, the libc may allocate a new arena with mmap and place it just beyond your mmaped region. A lot of libc functions need C-heap under the hood (e.g. calling C assert() will allocate C-heap to assemble the assert line). |
@tstuefe: Meanwhile I had also asked Klaus Möser who gave me a similar explanation and we both together examined /proc/pid/maps to understand that a runtime library had allocated the memory beyond my mmap region. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay (if tests are green).
@TOatGithub This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 57 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. As you do not have Committer status in this project an existing Committer must agree to sponsor your change. Possible candidates are the reviewers of this PR (@tstuefe, @RealCLanger) but any other Committer may sponsor as well. ➡️ To flag this PR as ready for integration with the above commit message, type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM but wait for the nightly testing results.
tests passed in dbg build; |
|
Yes, that looks unrelated. @navyxliu could you please take a look at JDK-8319104 ? |
@navyxliu : I have already taken over JDK-8319104, started analyzation, found the reason for the SIGILL and are working now on a fix for the root cause. |
Checks still run fine with the latest switch to os::is_readable_range. Therefore: /integrate |
@TOatGithub |
/sponsor |
Going to push as commit d6ce62e.
Your commit was automatically rebased without conflicts. |
@MBaesken @TOatGithub Pushed as commit d6ce62e. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
@@ -211,7 +211,8 @@ bool MallocTracker::print_pointer_information(const void* p, outputStream* st) { | |||
const uint8_t* here = align_down(addr, smallest_possible_alignment); | |||
const uint8_t* const end = here - (0x1000 + sizeof(MallocHeader)); // stop searching after 4k | |||
for (; here >= end; here -= smallest_possible_alignment) { | |||
if (!os::is_readable_pointer(here)) { | |||
// JDK-8306561: cast to a MallocHeader needs to guarantee it can reside in readable memory | |||
if (!os::is_readable_range(here, here + sizeof(MallocHeader) - 1)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I noticed this late, but the " - 1" looks wrong here, because is_readable_range() checks for < to
, not <= to
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Dean, thanks for finding this. I opened https://bugs.openjdk.org/browse/JDK-8319542 to address this and will fix it in a timely manner.
MallocTracker::print_pointer_information in src/hotspot/share/services/mallocTracker.cpp is called to check the highest pointer address of the reserved region. To do so it aligns the test pointer down to the next 8 Byte boundary and casts this address to class MallocHeader in order to use this classes eye-catcher member _canary for validation. Method looks_valid() dereferences _canary's content. _canary has an offset of 14 bytes relative to the class. Therefore it resides outside the reserved region for the highest pointer address, which causes a segmentation violation.
We would expect the same error also for other platforms than AIX as memory is read, which is not allocated. Interestingly, Linux seems to allow this access for 5 times 4K above the reserved region.
As a solution, looks_valid() should check _canary's address as being invalid, and return false immediately.
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/16381/head:pull/16381
$ git checkout pull/16381
Update a local copy of the PR:
$ git checkout pull/16381
$ git pull https://git.openjdk.org/jdk.git pull/16381/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 16381
View PR using the GUI difftool:
$ git pr show -t 16381
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/16381.diff
Webrev
Link to Webrev Comment