Why do we normally store the return addresses near to the local variables in the first place, again? There are so many downsides.
Why do we normally store the return addresses near to the local variables in the first place, again? There are so many downsides.
In exchange, it becomes very difficult for the stack smashing to corrupt the return address.
[1] https://en.wikipedia.org/wiki/Forth_(programming_language)
STOIC, a variant of Forth, includes a file stack when loading words
The dictionary pointer can also be manipulated in some dialects. That can be used directly as the stack variant of the arena allocator idea. It is particularly useful for text concatenation.
[1] https://forth-standard.org/standard/search [2] https://forth-standard.org/standard/core/MARKER
The advantage of storing them elsewhere is not quite clear (unless you have hardware support for things like shadow stacks).
You'd have to argue that the cost of moving things to this other page and managing two pointers (where one is less powerful in the ISA) is meaningfully cheaper than the other equally effective mitigation of stack cookies/protectors which are already able to provide protection only where needed. There is no real security benefit to doing this over what we currently have with stack protectors since an arbitrary read/write will still lead to a CFI bypass.
The classic buffer overflow issue should spring immediately to mind. By having a separate return address stack it's far less vulnerable to corruption through overflowing your data structures. This stops a bunch of attacks which purposely put crafted return addresses into position that will jump the program to malicious code.
It's not a panacea, but generally keeping code pointers away from data structures is a good idea.