Bugtraq mailing list archives

Re: machine independent protection from stack-smashing attack


From: John Viega <viega () LIST ORG>
Date: Thu, 10 Aug 2000 09:05:57 -0700

Our understanding is that the biggest reason why StackGuard hasn't
been ported to more architectures is that there's not really a
portable source of randomness available, such as a /dev/random.  It
wouldn't be all that hard to just port StackGuard to each
architecture; sure, you would either need to add
architecture-dependent code for each platform, or it would need to be
rewritten in a way that operated on the GCC internal representation
(which may or may not require a compiler change to allow easy access
to the return address) However, neither is all that hard.  Moreover,
one of these solutions is potentially necessary.

In particular, you fall prone to the problem that Crispan recently had
to fix with StackGuard; the canary is not bound to the actual return
address, so in some cases it is possible to "jump" the canary.  You
are using boundary canarys instead of xor canarys.

Sure, you're lining up arrays next to each other, but that doesn't
solve every case.  Consider the following example, slightly modified
from the StackGuard page:

foo(char * arg) {
    char *  p[1];    // a vulnerable pointer
    char a[25];    // the buffer that makes the pointer vulnerable
    p[0] = arg;
    gets(a);    // using gets() makes you vulnerable
    gets(p[0]);    // this is the good part
}

You could fix this particular problem by having one guard variable per
buffer.  However, we're not completely convinced that there still
wouldn't be some way to circumvent the mechanism; We feel much better
when the return address is actually tied in, for example, by XORing in
the canary.

Another problem comes up in the section on "pointer protection".
Let's say you have the following code:

void f(int x, void (*p)()){
  void (**p2)() = &p;
  ...
}

Assuming we understand you correctly, it is effectively rewritten as
such:

void f(int x, void (*p)()){
  void (*tmp1)();
  void (**p2)() = &tmp1;
  ...
}

Even though you assert otherwise, this does break the ANSI C standard,
because the standard requires the value of p2 to equal to the address
following &x.

Nonetheless, we don't think this is such a horrible way to break the
standard, given the protection it affords and the rarity of programs
that rely on this behavior.

In short, we believe the following:

1) Your patch is not all that portable because of its reliance on a
source for secure random numbers, for which there is not currently a
portable solution.

2) StackGuard provides better protection in most cases, and wouldn't
be all that hard to port.

3) We do like your idea of moving variables around and protecting
function pointers, even if it isn't perfect.  However, it really does
need to be integrated in a way that doesn't defeat anyone's
expectations when using the compiler, yet still affords people
protection by default.

Note that this kind of protection doesn't need to be implemented as a
compiler hack.  We've written a tool along with Greg Hoglund that we
call SO WHAT. It works with Visual C++ by wrapping the compiler with a
preprocessor.  The preprocessor inserts assembly code at the beginning
of functions, and prior to function returns.  At the beginning of the
function, the return address is XOR'd with a canary.  At the exit
points, it is XOR'd back.  This technique doesn't give you the chance
to recover from attacks gracefully because if there's an attack, you
jump to a random memory address.  However, this could be fixed pretty
easily by sticking the XOR'd canary into the first local instead of
just XORing the return address directly; we were just building
something quick and dirty.

The advantage here is that you can port this technique to any compiler
on any platform just by adding a few lines of assembly, and then
writing a small bit of code to hook the thing up to a compiler (one
thing you have to do is always make sure that frame pointer omission
is turned off on most platforms).  We basically provide the exact same
protection you get by using StackGuard, but implemented in a way
that's easy to port to any platform and compiler.  All you need is a
good random number generator.

We'll probably release the tool for free once we finish building a
good entropy accumulator for NT (and validate our Yarrow
implementation), so that we can be confident of the quality of our
random numbers.  We expect that to be about two months.  In the
meantime, it would be really easy to port this to any platform using
GCC that has managed to install /dev/random, if there's interest in
that.

John Viega and Tim Hollebeek


On Wed, Aug 09, 2000 at 06:59:49PM +0900, Hiroaki Etoh wrote:
I have been investigating a machine-independent change to GCC that
would generate code to protect applications from stack-smashing attacks.
The main characteristics are low performance overhead of the protection
code, protecting against different varieties of stack-smashing attacks,
and supporting various processors. A research report is ready on
the web (http://www.trl.ibm.co.jp/projects/security/propolice).

I would like some feedback whether it is worth pursuing getting it
assigned to the FSF for inclusion in GCC.

---
Hiroaki Etoh,  Tokyo Research Laboratory, IBM Japan


Current thread: