Skip to content

runtime: Race condition in map_fixed on Linux? #13256

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

Closed
eloff opened this issue Nov 15, 2015 · 8 comments
Closed

runtime: Race condition in map_fixed on Linux? #13256

eloff opened this issue Nov 15, 2015 · 8 comments
Milestone

Comments

@eloff
Copy link

eloff commented Nov 15, 2015

I was reading the code in mem_linux.go, and discovered what seems to be a race condition in mmap_fixed. If a call to mmap happens between the check addrspace_free(v, n) and mmap(v, n, prot, flags|_MAP_FIXED, fd, offset), then another mmap that happens between the two calls could, at least in theory, return a region within the same address space. The subsequent mmap fixed will happily succeed, even if there is an existing mapping for part of that address space.

func mmap_fixed(v unsafe.Pointer, n uintptr, prot, flags, fd int32, offset uint32) unsafe.Pointer {
 p := mmap(v, n, prot, flags, fd, offset)
 // On some systems, mmap ignores v without
 // MAP_FIXED, so retry if the address space is free.
 if p != v && addrspace_free(v, n) {
     if uintptr(p) > 4096 {
         munmap(p, n)
     }
     p = mmap(v, n, prot, flags|_MAP_FIXED, fd, offset)
 }
 return p
}
@ianlancetaylor ianlancetaylor changed the title Runtime: Race condition in map_fixed on Linux? runtime: Race condition in map_fixed on Linux? Nov 16, 2015
@ianlancetaylor ianlancetaylor added this to the Go1.6 milestone Nov 16, 2015
@ianlancetaylor
Copy link
Member

I think you're right, but note that I think it can only happen if the Go program calls syscall.Mmap or if it calls C code that calls mmap. Unfortunately I don't see how we can fix this for the case of C code calling mmap.

@minux
Copy link
Member

minux commented Nov 16, 2015 via email

@ianlancetaylor
Copy link
Member

@minux I agree that the runtime won't collide with itself, but a separate goroutine might be running at the same time and it might call syscall.Mmap explicitly.

@minux
Copy link
Member

minux commented Nov 17, 2015 via email

@ianlancetaylor
Copy link
Member

Ah, yes, I see what you mean. We are only in trouble with MAP_FIXED, and that is not a case that is worth worrying about.

I'm going to close this issue. @eloff please feel free to reopen if you think we are missing something.

@eloff
Copy link
Author

eloff commented Nov 18, 2015

I think it's OK to close, it's in a fallback path for who knows which OS
that doesn't handle hints with mmap. However, is not clear to me that it
could only happen with MAP_FIXED, there seems to be no reason to me why a
regular mmap can't succeed on another thread and return that address. It
seems to imply a lot more inside knowledge of how mmap works on a variety
of unixy systems than what I'm comfortable with. It may well be possible,
but it's already on a rare code path and the circumstances around the race
are likely very rare or even impossible. Code that crashes very
occasionally is still useful, in fact that describes pretty much every
software system out there. It's fine by me to focus on more important
things and address this when/if bug reports come in from the wild.

On Tue, Nov 17, 2015, 4:25 PM Ian Lance Taylor notifications@github.com
wrote:

Ah, yes, I see what you mean. We are only in trouble with MAP_FIXED, and
that is not a case that is worth worrying about.

I'm going to close this issue. @eloff https://github.com/Eloff please
feel free to reopen if you think we are missing something.


Reply to this email directly or view it on GitHub
#13256 (comment).

@ianlancetaylor
Copy link
Member

An mmap without MAP_FIXED can't succeed, because the original mmap that ran before the call to addrspace_free did not succeed.

Well, I suppose it's possible that Go calls mmap, then some other thread calls munmap, then Go calls addrspace_free, then some other thread calls mmap, then Go calls mmap with MAP_FIXED. If there were a way to fix that we should do it, but I don't think there is.

@eloff
Copy link
Author

eloff commented Nov 18, 2015

The previous call ignored the hint, but it did succeed at another address.
It's a bit tough to imagine an algorithm that would let an unrelated mmap
succeed in another thread, giving it part of the address range checked as
free here. But I don't think it's impossible either, for the entire space
of imaginable implementations. But I also don't see a way to fix it. I'm
sure we've spent more energy on it already than the question deserves.

On Tue, Nov 17, 2015, 11:42 PM Ian Lance Taylor notifications@github.com
wrote:

An mmap without MAP_FIXED can't succeed, because the original mmap that
ran before the call to addrspace_free did not succeed.

Well, I suppose it's possible that Go calls mmap, then some other thread
calls munmap, then Go calls addrspace_free, then some other thread calls
mmap, then Go calls mmap with MAP_FIXED. If there were a way to fix that we
should do it, but I don't think there is.


Reply to this email directly or view it on GitHub
#13256 (comment).

@golang golang locked and limited conversation to collaborators Nov 17, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants