On Thu, 2005-01-06 at 15:47 -0600, Robert Shearman wrote:
Actually, we shouldn't be generating assembly code on the fly. If you have more than say 16 proxies in a process then it is actually cheaper in terms of memory usage and cache locality to have a set of compiled entry points that can be shared by all proxies.
Yeah maybe, I'm not sure how Windows does it. From reading the comments in rpcrt4 it looks like they do have pre-compiled proxy entrypoints. Begs the question of what happens when there are more interface entry points than pre-compiled marshaller entrypoints of course. Maybe they can do both?
It is even better if you consider the fact that we shouldn't be allocating the memory for the code from the heap, but should be requesting an executable page of memory for each.
We don't allocate these from the process heap, we use a VirtualAlloc to get executable memory. I fixed that a while ago.
At the moment that's 1 page per set of proxy thunks (IMHO we shouldn't call them "asm stubs" like the code does, that's a recipe for permanent brain lesions at the moment), but we could easily switch it back to using HeapAlloc with a typelib marshaller specific heap created like so:
HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 1024 * 4, 1024 * 64);
Just for the record, PaX and execshield are trying to solve problems that are much better solved by other methods that don't break backwards compatibility. One of the best methods is introducing a terminator canary value between the return address and variables stored on the stack.
This can't do everything. It protects against return-to-libc style attacks but there are other stack based attacks that it doesn't work for (if I remember correctly).
It also has the obvious disadvantage of not working with older binaries too, though given how much these sorts of technologies break .....
Obviously, this requires compiler support (which GCC currently lacks, I believe),
gcc4 contains the ProPolice/SSP patches from IBM which can produce stack canaries. It's a looming binary portability problem unfortunately, the location it jumps to in the case of a stack smash is a symbol in glibc, so it's pretty likely that if you compile binaries with it they won't work everywhere. At least not for a very long time.
I might be jumping to conclusions, and anyway if that really is the case I'd be interested in writing a patch to gcc to release it from the glibc dependency. It'd be nice to use it in Crossover.
It even prevents exploits that PaX/execshield can't, like "return to libc" where the return address is overwritten by the address of another function so that execution jumps into that function.
That's why the DSOs and binary load addresses are randomised, you can't do a return to libc attack if you don't know where libc is. You can guess of course but that doesn't let you write a worm that propogates at will.
thanks -mike