ASLR sometimes stops working on Vista with 1.7? [was: Re: Cygwin 1.7 release (was ...)]
Corinna Vinschen
corinna-cygwin@cygwin.com
Fri Jun 5 21:30:00 GMT 2009
On Jun 5 14:44, Charles Wilson wrote:
> Corinna Vinschen wrote:
> > However, if I rebase the DLL to some other spot, like 0x65000000, then
> > the DLL is loaded at that address exactly, and everything works fine. I
> > still don't think this has anything to do with ASLR. ASLR only
> > complicates the picture. AFAICS, there's no guarantee that the address
> > computed by ASLR will help forever. It only eases the underlying
> > problem by chance if the addresses happen to have a low chance for
> > collision.
>
> One of the side effects of ASLR is to, in effect, perform a custom
> rebase for every dynbase-enabled DLL, that is (a) unique to the usage
> pattern of your machine workflow since you (booted/logged on), and (b)
> includes not just cygwin DLLs but also all normal system DLLs so marked,
> and (c) persists for the entirety of the current boot/logon session.
> This means very little chance of collision at all, AFIACT, at least not
> any that arise from (new)ImageBase+codesize.
>
> For ASLR, all dynbase DLLs (including cygwin ones) get mapped to the
> range 0x50000000 to 0x78000000. If something ends up at 0x900000, either
> with +dynbase/ASLR or without, it's not directly related to ASLR...
That's what I'm trying to say. ASLR is probably helping in the normal
use case. But if the DLL's ALSR memory slot is taken by something else
(for instance, a non-ASLR DLL), the new DLL will have to be relocated by
the system, same as without ASLR. It might be a helpful technique, but
it's far from a one-size-fits-all solution.
> > The problem is not the fact that the DLL is rebased at all in the
> > parent. Even though in my case the address range 0x6ee00000-0x6ee08000
> > isn't taken by another DLL, it could be taken by memory dynamically
> > allocated by one of the formerly loaded DLLs.
>
> Really? This would have to be by virtue of some call OTHER than to
> cygwin's malloc, right?
In theory, yes, but not necessarily. malloc does not use the heap
exclusively. Big chunks of memory (>128K) are allocated using mmap()
with the MAP_PRIVATE|MAP_ANONYMOUS flags. Private anonymous maps are
implemented using VirtualAlloc with the MEM_TOP_DOWN flag.
> Because I thought cygwin maintained a single
> process heap way down low in memory...it's hardly likely for that heap
> to clash with 0x50000000...0x78000000 (or, for the original rebase,
> non-ASLR scenario, 0x68000000...downwards), for small allocations like
> this (e.g. where your solution of adding a single page to the
> DefaultOffset size as a buffer helps).
It's definitely not a collision with the heap which results in rebasing
the DLL in the parent.
> If it's a cygwin-linked DLL doing this (e.g. Dumper.dll) maybe it's a
> bug in that DLL, using the wrong mechanism to allocate memory (e.g. a
> direct call to VirtualAlloc or to (deprecated) GlobalAlloc or LocalAlloc
> functions?) ...Hmm, perl itself (incl. Dumper.dll) doesn't seem to.
>
> > The real shit starts with the fact that W7 (and Vista, too, apparently)
> > rebases the DLL to an address which is so very low in the address space
> > of the application.
>
> But why did it do this at all? In the normal "rebase" scenario (and
> assuming no dynamically allocated memory sucking up 0x68000000-level
> space), sure -- I could see some other system DLL interfering with where
> rebase wanted to put, e.g. Cwd.dll.
That's not the case. There's no DLL loaded into the address in
question. At least not if I ask WinDbg. Either the memory is taken by
something else (I don't know what it is), or the OS decides that DLLs
shouldn't spoon with each other (think of the children) and rebases the
DLL for decency.
[...time passes...]
WinDbg confirms that the memory is taken by something else. Dumper.dll
is located in the area 0x6ede0000 - 0x6eded000. The next three pages
from 0x6eded000 - 0x6edf000 are free. The following memory region from
0x6edf0000 - 0x6ee01000 (68K, huh?) consists of commited R/W pages
allocated in a single allocation call.
Examining the content of the commited memory region starting at
0x6edf0000 shows something surprising. After a couple of arbitrary
bytes, there's a 4 byte value 68, followed by the WCHAR string
\\?\C:\cygwin\lib\perl5\5.10\i686-cygwin\auto\Data\Dumper\Dumper.dll
which is exactly 68 wide characters long. The entire reminder of the
memory region is set to 0.
The fact that the path has a leading \\?\ points to something in
the Cygwin DLL allocating that memory, perhaps in dlopen. But why
at this memory address?!?
> > Some perl DLL (Dumper.dll?) allocates additional memory and that's right
> > after it's own image. That's where Cwd.dll is based to. Cwd.dll gets
> > rebased and ... poof.
>
> Right then. So...why? Seems odd that the dynamic allocation is occuring
> "up high" and not down in user_heap.
Absolutely. Especially after finding what's in that memeory region...
> >> Could it be possible that cygwin's dlopen (or fork) implementation is
> > Not that I can see. The memory for the data storing the loaded DLLs is
> > loaded from the parent memory into a stack slot. There's no other
> > memory allocation going on. Well, except when LoadLibrary already
> > failed.
>
> Ack. Good. Cygwin's fork/exec code is much much scarier to me than
> memory allocation...
Not good. I'm puzzled where this allocated 68K region is exactly coming
from, but it really looks like something which occurs in or near dlopen.
I'm going to debug this further tomorrow. I guess that goes without
saying, but I'd be glad for any help.
Corinna
--
Corinna Vinschen Please, send mails regarding Cygwin to
Cygwin Project Co-Leader cygwin AT cygwin DOT com
Red Hat
--
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
Problem reports: http://cygwin.com/problems.html
Documentation: http://cygwin.com/docs.html
FAQ: http://cygwin.com/faq/
More information about the Cygwin
mailing list