
Retguard: OpenBSD/Clang - brynet
https://marc.info/?l=openbsd-tech&m=150317547021396&w=2
======
protomyth
I love the line: _I spoke a lot with Todd Mortimer. Apparently I told him that
I felt return-address protection was impossible, so a few weeks later he sent
a clang diff to address that issue..._

~~~
nstott
I know right

Strong opinions, loosely held

------
busterarm
The volume and quality of tools coming out of the OpenBSD community in recent
years has been absolutely awe-inspiring.

I'm presently able to do the entirety of my personal project work on the OS
and I'm only a couple of tools from being able to do the same professionally.

Keep it up, y'all.

------
RolfRolles
I also must be missing something. XORing the return address on the stack with
the stack pointer is similar to other stack protection mechanisms. I forget
the precise name of it, but I'm pretty sure one of the existing stack
protection tools does exactly this? MSVC's /GS feature is similar but slightly
different in that it XORs the return address with a random value initialized
on module load.

However, the claim that ROP is impacted seems a bit flimsy to me. After all,
ROP only requires that the C3 (RET) or C2 xx yy (RETN YYXX) byte sequence be
present at the end of it; these sequences do occur at the end of a function,
but they also occur in other places (such as anywhere the byte C3 arises in
compiled machine code). ROP tools are programmed to look for the C3/C2 XX YY
sequences and do not know or care whether these sequences are at the end of a
function. The post is claiming that by transforming the ends of functions, ROP
will be affected; but given that it seems to makes no attempt to remove C3 and
C2 bytes from elsewhere in the machine code, that ROP tools will in fact
continue to work just fine.

Basically the whole thesis of this patch seems to be that "existing stack
protection methods will change function epilogues and therefore break ROP". I
don't think it will have much of an effect on existing ROP tools. What am I
missing?

~~~
ycmbntrthrwaway
> but given that it seems to makes no attempt to remove C3 and C2 bytes from
> elsewhere in the machine code, that ROP tools will in fact continue to work
> just fine.

To use ROP you need not only the RET instruction, but the code before it. You
want to execute some existing function and return only then, not just return.

Buffer overflow attacks rely on overwriting return address, which is stored on
the stack, with address of some code that attacker wants to execute. But if
before returning the function XORs the value attacker used with some value he
does not know, it is impossible for attacker to start ROP chain.

Though like with ASLR, it is possible to defeat this with a leak. If attacker
can defeat ASLR, he likely can defeat this as well.

~~~
RolfRolles
As I said to the other user who replied to a similar comment, these
observations apply only to exploitation of stack buffer overflows, and hence
don't rebut what I've said about this not mitigating ROP as a general
technique (which is also used in the exploitation of non-stack-based
vulnerabilities like use-after-free).

~~~
ycmbntrthrwaway
You have not replied to this:

> To use ROP you need not only the RET instruction, but the code before it.
> You want to execute some existing function and return only then, not just
> return.

Ok, you found RET in some unexpected place, like an immediate value. But do
you want to execute the code before it? Most likely it is just garbage.

Usually you want to return to mprotect() and then chain somewhere else from
it. With this mitigation even if you manage to jump to mprotect() function,
you will not be able to make it chain to the next function you want.

~~~
RolfRolles
Yes, gadgets arising from non-epilogue instances of C2/C3 are used frequently.
In fact they are most often critical and the ROP exploit would not work
without them.

------
jacquesgt
I feel like I’m missing something here. An infoleak is required to
successfully ROP against ASLR (otherwise the attacker doesn’t know what to
overwrite the return address with). Once an infoleak is available, the address
of the stack can be leaked. I’m not really sure this does much beyond
requiring attackers to modify their existing exploits.

~~~
syncopate
It increases the complexity of the attack. Usually, stack cookies make ROP
harder these days but guessing the cookie only has a complexity of 8*256 (on
OpenBSD), but xor'ing the return address with another value does increase the
complexity even more. And that might be good news for programs that use fork a
lot (like nginx) and hence don't get a refresh for ASLR/stack cookies for
every request (like e.g. sshd on OpenBSD does [which does does fork/exec to
ensure ASLR/cookies are refreshed]).

~~~
hexadecimated
Perhaps OpenBSD should consider randomizing the per-process stack canary value
upon fork().

~~~
syncopate
How does that work? Should the kernel walk the stack to change all the saved
cookie values of the forked copy? I doubt the kernel even knows where the
saved cookie values are stored on the stack. Also, that would make fork quite
slow, depending on how the deep the stack was when the fork happened.

~~~
hexadecimated
The post-fork canary value could be paired with the stack pointer at which it
became valid. If not valid, the process could walk a linked list of pre-fork
canary and stack pointer pairs, to find the correct value to use. Would be
interesting to see the performance hit on such an approach.

~~~
tedunangst
Or not. The stack canary is not the only random value reset upon exec.

------
jnwatson
Microsoft has a much more sophisticated control flow integrity mechanism
called control flow guard [https://msdn.microsoft.com/en-
us/library/windows/desktop/mt6...](https://msdn.microsoft.com/en-
us/library/windows/desktop/mt637065\(v=vs.85\).aspx).

LLVM also has an impressive set of CFI capabilities:
[https://clang.llvm.org/docs/ControlFlowIntegrity.html](https://clang.llvm.org/docs/ControlFlowIntegrity.html).

The proposal just sounds like higher entropy stack cookies.

~~~
Mordak
I think the LLVM CFI options only apply to C++ programs?

Microsoft's CFG is cool, but works on the other end to this - by protecting
CALL instructions instead of RET.

Stack cookies are similar, yes. This mechanism combines two ASLR-randomized
values (the caller address and the stack address) to control program flow.
Stack canaries use a constant random cookie per object file to detect stack
smashing. Retguard raises the bar for successful ROP attacks, just as CFG
raises the bar for function pointer corruption attacks.

Full disclosure, I am the author of the clang diff that kicked this off. The
appeal of this mechanism is that it is cheap enough to apply in every
function, pollutes the ROP gadget space with instructions that permute the
next return address, and requires attackers to have more information in order
to kick off ROP chains (the address where they are writing their ROP chain). I
know about some of the other stuff people are working on (CPI seems
promising), and look forward to turning those things on when possible.
Meanwhile, this mitigation is cheap, localized inside every function, and
doesn't require any program modification in the vast majority of situations
(programs that inspect stack frames without consulting the unwind info may
have problems), so is fairly easy to turn on everywhere.

~~~
jnwatson
Sorry, you are correct. I was actually thinking of clang's SafeStack
([https://clang.llvm.org/docs/SafeStack.html](https://clang.llvm.org/docs/SafeStack.html))
and Microsoft's Return Flow Guard
([http://xlab.tencent.com/en/2016/11/02/return-flow-
guard/](http://xlab.tencent.com/en/2016/11/02/return-flow-guard/)). Both use
shadow or alternate stacks.

Regarding cost, a few years back, I implemented a shadow stack system via
static binary rewriting. The overhead was very low, 1-2%. SafeStack claims <
0.1%.

~~~
Mordak
Ah, Return Flow Guard is cool - I did not know that MS had done that!

I like SafeStack, but was disappointed to learn about the limitations with
shared libraries. Some SafeStack is better than no SafeStack though, and it
can probably be turned on without too much effort.

------
hungryimitator
Maybe we seen this before? :)

[http://i.imgur.com/DW1dqnV.png](http://i.imgur.com/DW1dqnV.png)
[http://i.imgur.com/vZnpKwL.png](http://i.imgur.com/vZnpKwL.png)

Seriously.. these projects should talk more about each others stuff..

------
brynet
Here's a better mail archive link: [https://marc.info/?l=openbsd-
tech&m=150317547021396&w=2](https://marc.info/?l=openbsd-
tech&m=150317547021396&w=2)

EDIT: Thanks mods? :-)

~~~
sctb
Thanks, we've updated the link from [https://marc.ttias.be/openbsd-
tech/2017-08/msg00349.php](https://marc.ttias.be/openbsd-
tech/2017-08/msg00349.php) to the original archive site.

------
miaklesp
This dude should choose a better font for his blog.

~~~
busterarm
I hope you're kidding, but for the uninitiated:

MARC, or marc.info, is the Mailinglist ARCive. You're reading email.

