|
|
Subscribe / Log in / New account

A return-oriented programming defense from OpenBSD

A return-oriented programming defense from OpenBSD

Posted Aug 31, 2017 18:07 UTC (Thu) by wahern (subscriber, #37304)
In reply to: A return-oriented programming defense from OpenBSD by sorokin
Parent article: A return-oriented programming defense from OpenBSD

The dual-stack approach was merged into Clang.

http://dslab.epfl.ch/proj/cpi/
http://clang.llvm.org/docs/SafeStack.html

Though IIUC there are still some unresolved integration and interoperability issues involving threading, dynamic memory, etc, that make SafeStack undesirable to use long-term until those issues are resolved.


to post comments

A return-oriented programming defense from OpenBSD

Posted Aug 31, 2017 22:18 UTC (Thu) by thestinger (guest, #91827) [Link]

The Clang implementation works well when paired with proper integration in libc, but glibc doesn't have that.

A return-oriented programming defense from OpenBSD

Posted Sep 11, 2017 13:29 UTC (Mon) by itvirta (guest, #49997) [Link] (3 responses)

> The dual-stack approach was merged into Clang.

So, if I got that right, they make another software controlled stack for variables/arrays that get their pointers taken,
and keep the rest in the usual hardware stack?

I've sometimes wondered why CPUs don't implement a separate, protected, stack for the CALL/RETURN instructions.
That should deal with all sorts of overwriting and adding return pointers, if the stack was made read-only or completely
inaccessible to other instructions. But I don't know if there would be some prohibitive cost to that.

A return-oriented programming defense from OpenBSD

Posted Sep 11, 2017 18:40 UTC (Mon) by wahern (subscriber, #37304) [Link]

From Table 1 of the Code-Pointer Integrity (2014) paper:

                   Safe Stack  CPS    CPI
-------------------------------------------
Average (C/C++)  |       0.0%   1.9%   8.4%
Median (C/C++)   |       0.0%   0.4%   0.4%
Maximum (C/C++)  |       4.1%  17.2%  44.2%
-------------------------------------------
Average (C only) |      -0.4%   1.2%   2.9%
Median (C only)  |      -0.3%   0.5%   0.7%
Maximum (C only) |       4.1%  13.3%  16.3%
-------------------------------------------
Table 1: Summary of SPEC CPU2006
performance overheads.

Safe Stack is the dual-stack mechanism. CPS(weak) and CPI (strong) are for dealing with function pointers in heap data.

A return-oriented programming defense from OpenBSD

Posted Sep 12, 2017 16:20 UTC (Tue) by zlynx (guest, #2285) [Link] (1 responses)

I believe that *every* recent CPU instruction set does a separate return stack. Well, as far as I can tell RISC-V puts it in a register, then it is up to a function caller to save the "ra" register wherever it wants before making the call. It can save it to the stack, a different stack or a linked list, the processor doesn't care. Itanium was similar, return addresses were saved in registers, and the registers would overflow into a separate stack.

If only people would stop relying on the x86 / amd64 ISA.

A return-oriented programming defense from OpenBSD

Posted Sep 12, 2017 18:32 UTC (Tue) by excors (subscriber, #95769) [Link]

RISC-V sounds similar to ARMv8 AArch64, where (if I understand correctly) the "BLR" instruction branches and stores the return address in the X30 (LR) register, and the "RET Xn" instruction returns to the address stored in some register, and that's the only proper way to call a function. A non-leaf function can preserve X30 however it wants; usually it will push/pop X30 on the stack associated with the slightly magic SP register, but the push/pop instructions (store-and-decrement/load-and-increment) can use any register as the index, so I think you could create a separate control stack for approximately zero cost (just one more reserved register) to keep the frame pointers and return addresses away from all the "char surely_this_is_big_enough[256];" buffers and other local variables.

(ARMv7/AArch32 is similar but more confusing, because there are lots of mostly-deprecated ways of returning by using PC as a destination register, and you usually push/pop LR/PC in the same instruction as all the other registers you want to preserve (whereas AArch64 can only push/pop a pair of registers at once), and the Thumb instruction encoding has lots of limitations, and there are only half as many registers as AArch64, so a separate control stack might be significantly more expensive there.)

A return-oriented programming defense from OpenBSD

Posted Sep 16, 2017 22:16 UTC (Sat) by areilly (subscriber, #87829) [Link]

The dual-stack method is also the basis of the Web Assembly ABI, which (via emscripten) is probably why it's in clang already. Coming (or already in) a web browser near you.


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds