"Jonathan A. Zdziarski" <jonathan@networkdweebs.com> wrote: > I think this is overkill and will probably cause your applications to > run much slower than they already do. Ack. Sacrificing a register is probably pretty bad for x86. I see more problems, though. The usual memory layout is to have code and fixed size data somewhere at the start of the virtual address space, then above that the heap and the stack at the end. This allows to let the heap top grow towards the stack bottom, allowing for maximum usage of the virtual address space which is small enough on x86 anyway (4GB isn't much for some apps ...) Having another thing to place leaves the question of where to place that without getting in the way for both common cases of apps with high stack usage or high heap usage. And please do not argue for using a segment of its own. That causes really evil headaches when handling pointers. > I don't see why one couldn't simply put the variable information > *after* the rest of the stack information, instead of before, Because that is not how C (and other languages that use its calling convetion) works. The point is, that you can open subscopes anywhere like this: int some_function(int some_parm) { int some_var; ... { int some_local_var; } } Using the usual layout that looks a bit like this: some_parm ret-address some-locally-saved-regs some_var some_local_var while inside the inner brackets, and the same just without the last line while outside. This is easy to implement and partially even supported by the CPU design. It is hard however to keep the ret address below anything else, as you would have to continuously copy it around. AFAIK one could configure the stack to walk up instead of down, but that would pose a similar problem WRT the traditional memory layout and stuff like the traditional brk()/sbrk(). Moreover it just helps in a few specific cases, as do many other approaches. An increasingly popular problem are format string and stack smashing attacks. Especially format string attacks are often capable to write to any byte in memory. This way any function pointer that is called later is at risk - no matter what you do to protect yourself using memory separation techniques. Of course the problem might be mitigated severely, as you cannot just download the shellcode, if all the writeable areas are not executable anymore, but that just moves the challenge to find some clever way to abuse functions within the original code. I have no doubt people will find a way - unicode exploits exist as do exploits that can only use a specific subset of characters. > and have the kernel zero out the next stack frame before it gets written > to (although this may cause some performance problems in itself). Highly recursive programs might not be amused. Try running a program that extensively uses malloc with efence for a taste of what happens. A simple thing like a function call should very probably not cause the System to fiddle with MMU tables ... hmm - or what did you mean with zeroing out? > This would prevent a buffer overflow from A) overwriting SS:ESP and > B) overflowing code onto the next stackframe. Basically a stack canary should do the same. So I agree with some others here: Fix the problem, not the symptom. And the problem is, that buffers are overflowed, because the APIs for string handling are ... umm ... let's say ... suboptimal. A common length-checking set of functions along the lines of the C-library str* and sprintf functions plus a few others would already help a lot. Not that these do not exist ... the problem is to teach people to exclusively use them. In a similar way, automatic overflow checking (e.g. selectable by a compiler pragma so we don't loose performance, when it is not critical anyway) would prevent quite some of the integer-overflow problems we are seeing. CU, Andy, waiting for another rout of out-of-office junk. -- = Andreas Beck | Email : <becka@uni-duesseldorf.de> =