Years later, Todd Mortimer and I developed RETGUARD. At the start of that initiative he proposed we protect all functions, to try to guard all the RET instructions, and therefore achieve a state we call “ROP-free”. I felt this was impossible, but after a couple hurdles the RETGUARD performance was vastly better than the stack protector and we were able to protect all functions and get to ROP-free (on fixed-sized instruction architecures). Performance was acceptable to trade against improved security.
[…]RETGUARD provides up to 4096 cookies per DSO, per-function, but limited to avoid excessive bloat. It is difficult to do on architectures with very few registers. Code was only written for clang, there is no gcc codebase doing it. clang code for some architectures was never written (riscv64).
I hope that sets the stage for what is coming next.
We were able to enable RETGUARD on all functions because it was fast.
Look, I have no clue what any of this means. None at all. However, I do somewhat grasp this is a big deal… I just need OSNews readers to explain in layman’s terms why, exactly.
Here’s a far better article for understanding the concepts behind return-oriented-programming and the retguard technique.
https://lwn.net/Articles/732201/
Retguard, much like ASLR, is a mitigation designed to provide increased probabilistic security from attackers exploiting code vulnerabilities. But they’re only addressing the symptoms rather than the root cause. Personally I am of the opinion that these vulnerabilities shouldn’t exist in the first place. We as an industry need to do better by breaking our dependency on insecure languages including C, at least in contexts where security is critical. While C remains pervasive for system level code, it’s encouraging to see that many developers are finally investing in alternatives like rust. My hope is that one day safe languages will be the norm and insecure language mitigation techniques become unnecessary.
After almost 30 years of banging the keyboard, I have almost given up on the pipe dream of having a good language that has safety baked into it. I say that because of all the promised made through the years with nil to show for it especially when typically performance took massive hits. With that, rust does appear to have all the makings of a solid language with very minimal performance lost. The best move so far has been for rust to be moved out from under Mozilla (nothing against Mozilla) and placed under the care of it’s own group. With MS making serious efforts to adopt it as well as Linux on the other side of the fence sure gives credence to it’s potential.
dekernel,
Yeah, a lot of the justification for unsafe languages like C is that developers can do what they want without being hindered by the performance costs of runtime safety checks. Low level languages are expected to perform well without a tradeoff compared to managed languages like java where there can be significant performance differences.
This is why we need rust (or at least something like it) to innovate with robust safety checks at compile time. Now our industry can reconsider the position that we can only have safety OR performance. Rust is hopefully just one of many languages that will legitimately offer both performance and proven correctness in the future.
My biggest gripe with rust conversions right now is that we’re loosing a lot of rust’s potential using it behind C API interfaces, effectively terminating rust’s safety checks at the API barrier. Obviously we do this because C is the greatest common divisor that every language has to be compatible with. We’re not realistically ready for a project like linux to switch to rust APIs, but until we do we’re still limiting the full potential of safe languages.
Even C++ developers frequently have to interface C++ code with C APIs effectively nullifying C++ features at the API barrier. I’d like for the industry to standardize on a higher level interfaces so we’re not stuck with C APIs until the end of time, but I know there are a lot of obstacles in the way…baby steps!
OSN seriously needs tech contributors to break down these articles. But good read nonetheless.
It sounds like they’re developing a software-only version of the Control Flow Integrity mechanisms Intel and AMD are starting to add to newer generations of CPUs, such as the Shadow Stack support that’s part of Intel’s “Control-flow Enforcement Technology”.
…which would make sense, given that OpenBSD developed W^X as a software-only version of CPU NX-bit support for marking memory as either writable or executable but not both.
(For those not familiar with it, the idea behind Shadow Stack is that, whenever the CPU executes a CALL opcode, in addition to pushing the return address onto the regular stack, it also pushes it onto a backup stack in memory that’s not mapped into the program’s address space. Then, when a RET is executed, it checks to make sure the two addresses still match and faults if they don’t. The other half of Intel CET is called Indirect Branch Tracking and is intended to protect the other side of the coin, catching attempts to corrupt JMP and CALL rather than the RET. IBT requires that code be recompiled so that every valid jump/call target begins with a special ENDBRANCH opcode marking it as such.)
..in fact, I almost forgot to mention, but Microsoft has been doing similar things with Microsoft Control Flow Guard and the upcoming eXtended Flow Guard.