[PROPOSAL] Adding support for -fstack-protector-strong

Hello,

I plan to implement "Stack Smashing Protection - Strong" support in LLVM.
Below is a description of this feature and an overview of the implementation
plan. I have divided up the implementation into stages that can be delivered
incrementally.

I'm looking for any feedback (suggestions, requests, etc) before I actually
begin the work.

Thank you!
Josh

This sounds like something that would be triggered for any function containing a block, even if the block doesn't do anything that is potentially unsafe. It also sounds like it would be triggered for a lot of C++ function s that allocates an object on the stack and call methods on them. Is it possible to tighten up the heuristic slightly so that this isn't the case? For blocks, in particular, you always have the IR for the block invoke function available in the compilation unit where you are creating the block (on the stack) and so you can potentially verify at compile time whether it is doing anything unsafe to any of the bound variables.

David

Hello,

I plan to implement "Stack Smashing Protection - Strong" support in LLVM.
Below is a description of this feature and an overview of the implementation
plan. I have divided up the implementation into stages that can be delivered
incrementally.

I'm looking for any feedback (suggestions, requests, etc) before I actually
begin the work.

If you're looking for a project to learn about LLVM and Clang, then I think this is a great project. If the LLVM /Clang community wants this feature so that it is feature-compatible with GCC, then I think including this feature into LLVM/Clang makes sense.

If you want to protect applications from attack, then I think there are far more productive and interesting things to work on than stack protectors. Stack protectors are really a hack and, at best, only protect against a single kind of attack (and with buffer overread attacks, I'm not even sure if they do that very well). Even if they work against stack buffer overflows, stack protectors don't protect the application from heap overflows, invalid free attacks, dangling pointer attacks, and non-control data attacks.

The fastest countermeasure that I think is worth looking at is Control Flow Integrity (CFI); CFI adds checks to return instructions and indirect jumps to ensure that they're jumping to a valid target address. As far as I know, there's no control-hijack attack that works against it, although non-control data attacks are still possible. The fastest CFI implementation at present has an average overhead of 7.74% on 32-bit x86, and by using a very conservative callgraph, you can use it without whole program analysis. I've got the LLVM implementation from the authors at LeHigh and am updating the code for x86_64 and LLVM 3.1 for use in one of my research projects. If you're interested in the code, I can ask them if they'd be willing to release the code as open-source.

Optimizations for memory safety tools like ASan, SAFECode, and SoftBound would be even better since they also stop non-control data attacks. Getting good performance out of them is difficult, though, and depending on what sorts of overhead you're willing to tolerate, getting good performance is still an open research question.

You might want to check out the memory safety menagerie (Memory Safety Menagerie). It has lots of papers on various techniques and optimizations for those techniques. You might find something that will give you the security you want at the performance you need.

In short, I think working on something that provides more comprehensive protection is better than working on a partial hack.

My two (maybe four?) cents.

-- John T.

Indeed. For a homework assignment, I had my students perform a buffer overflow on the stack that overwrote the stack canary and still exploit an admittedly trivial target program.

David Chisnall wrote:

   1) An address of a local variable is taken in such a way as to expose the
      address of a stack location.
     - Example: the address of a local on the RHS of an assignment, the
       address of a local passed into function.

It also sounds like it would be triggered for a lot of C++ function s that
allocates an object on the stack and call methods on them. Is it possible
to tighten up the heuristic slightly so that this isn't the case?

I don't see any inherent difference (for this purpose) between
    void foo() {
      int x;
      someFunc(&x);
    }
and
    void foo() {
      SomeClass x;
      x.someNonStaticMethod();
    }
It's just that C++ is so good at obscuring the details. Granted there is
no & operator in the second case, but the address of the stack-local object
is available to the called method without any hijinks, just like the address
of the stack-local variable is available to someFunc in the first case.

--paulr

Right, in both cases a stack address is exposed. Both usages are so
common place that this will end up triggering protectors for a lot of
functions. In cases where the IR of the called function/method is
available, then it sounds reasonable to verify whether the callee
actually does anything "unsafe" with the address before triggering a
protector.

I'm not especially familiar with Blocks, but given that the IR is
always available then it makes sense to tighten up the heuristic
for Blocks first. After that it could be improved/tweaked for methods.

I think once the initial strong heuristic is in place, then we can
improve/tweak it as desired to accommodate these issues.

- Josh

If you're looking for a project to learn about LLVM and Clang, then I
think this is a great project. If the LLVM /Clang community wants this
feature so that it is feature-compatible with GCC, then I think
including this feature into LLVM/Clang makes sense.

Yes, this is one reason - it seems like a reasonable project to get more
involved with the LLVM and Clang community. The other reason is that
this feature has been requested by developers at my place-of-work.

If you want to protect applications from attack, then I think there are
far more productive and interesting things to work on than stack
protectors. Stack protectors are really a hack and, at best, only
protect against a single kind of attack (and with buffer overread
attacks, I'm not even sure if they do that very well). Even if they
work against stack buffer overflows, stack protectors don't protect the
application from heap overflows, invalid free attacks, dangling pointer
attacks, and non-control data attacks.

I agree: Stack protectors only protect against one very specific kind of attack.

The fastest countermeasure that I think is worth looking at is Control
Flow Integrity (CFI); CFI adds checks to return instructions and
indirect jumps to ensure that they're jumping to a valid target
address. As far as I know, there's no control-hijack attack that works
against it, although non-control data attacks are still possible. The
fastest CFI implementation at present has an average overhead of 7.74%
on 32-bit x86, and by using a very conservative callgraph, you can use
it without whole program analysis. I've got the LLVM implementation
from the authors at LeHigh and am updating the code for x86_64 and LLVM
3.1 for use in one of my research projects. If you're interested in the
code, I can ask them if they'd be willing to release the code as
open-source.

This sounds quite interesting - I'll definitely do some investigation into CFI.
If the authors are willing to release the source code as open-source
that would be great.

Optimizations for memory safety tools like ASan, SAFECode, and SoftBound
would be even better since they also stop non-control data attacks.
Getting good performance out of them is difficult, though, and depending
on what sorts of overhead you're willing to tolerate, getting good
performance is still an open research question.

You might want to check out the memory safety menagerie
(Memory Safety Menagerie). It has lots of papers on
various techniques and optimizations for those techniques. You might
find something that will give you the security you want at the
performance you need.

In short, I think working on something that provides more comprehensive
protection is better than working on a partial hack.

My two (maybe four?) cents.

Thanks for the input. I agree that there are better security techniques
and countermeasures than SSP. At the end of the day SSP-strong is still
something I want to implement. Still, you have given me some food for
thought and a number of interesting tools and techniques to explore.

- Josh