Return-oriented programming (ROP) is now a common technique for compromising systems via a stack-smashing vulnerability. Although restrictions on executing code on the stack have mostly put an end to many simple stack-smashing attacks, that does not mean that they are no longer a threat. There are various schemes in use for defeating ROP attacks. A new mechanism called "RETGUARD" is being implemented in OpenBSD and is notable for its relative simplicity. It makes use of a simple return-address transformation to disrupt ROP chains to hinder their execution and takes the form of a patch to the LLVM compiler adding a new flag.
(Score: 2) by Wootery on Wednesday September 13 2017, @04:00PM (4 children)
We could go even further and have four: one for arguments, one for returned values, one for temporaries, and one for return-to (instruction pointer) addresses.
Ideally what we'd want is for the return-to stack to be inaccessible except for by the call/return instructions. This would be similar to what Intel's CET does, but without the duplication. (Of course, CET's hands are tied for backward compatibility.)
Ignoring the write-prevention, yes. Presumably a software solution could do something similar, especially with kernel support; CET 'just' does something with page tables after all.
You're right, that would be a very different question.
(Score: 2) by Virindi on Wednesday September 13 2017, @08:49PM (3 children)
You're right, not sure why I wasn't thinking about that. Clearly it is helpful to have the page containing the return address stack, have write protection against "normal" data write instructions.
(Score: 2) by Wootery on Thursday September 14 2017, @08:14AM (2 children)
I figure you could do a similar thing in software (i.e. block 'ordinary' instructions from accessing that stack) using syscalls, unless I'm missing something.
(Score: 2) by Virindi on Thursday September 14 2017, @09:25AM (1 child)
How? It would have to be written to when you make a call. I am not aware of some easy mechanism to achieve this.
I double checked the Intel reference manual, and attempting a call instruction when the next stack location is a non-write page results in a processor exception. So if you want to implement this in software, you'd have to have the OS deal with this exception and check on whether a call instruction was actually made (and not a normal memory write), make the push, then resume. This seems like a heck of a lot of overhead for every call!
Or am I missing something?
(Score: 2) by Wootery on Thursday September 14 2017, @01:49PM
You're right, there would be an awful amount of overhead there.
I don't think there's any efficient mechanism to restrict access to a page to only certain functions.