Smashing the Stack: prevention?

nate (nate@MILLCOMM.COM)
Sun, 27 Apr 1997 20:31:55 -0400

Aleph One's excellent article "Smashing the Stack For Fun & Profit"
in Phrack 49 (http://www.fc.net:80/phrack/files/p49/p49-14)
got me started a few months back looking into different
people's approaches to the smash the stack/buffer overflow problem.
As each new vulnerability appears on this list and BoS, CERT, etc.,
9 of 10 times it's a buffer overflow. A number of high-profile cases over
the past few months has heightened awareness of what this problem is,
what's vulnerable, how it works, and (maybe?) how to prevent it. The
April 1997 USENIX association newsletter also has a (very) brief article
about this "Stack Smashing, What to do?" by Shawn Instenes. In reading
the above mentioned articles, this list, and scowering every dark corner
of the net, I have put together a few different methods folks are using
to fight the buffer overflow problem, i'm looking for everyone's input
and ideas for solutions to the buffer overflow problem..

1. 'you gotta change the code'
This one is obvious; people must change their SUID programs'
source code to avoid nasty things like gets() sprintf() strcat() and
strcpy() using things like fgets() strncat() strncpy() as substitutes.
(there are many more 'problem' functions, i'm only listing a few here).
Any unbounded byte copying is suspect to buffer overruns, and needs to
be examined and changed. The drawbacks are obvious, thousands of lines
of source need to be changed/examined, re-written. However, many people
agree that this is the "right/proper/only" way to insure SUID 0 programs
are not exploited. Do we have a comprehensive list of function calls to
avoid, and suitable replacements? Spaf has some listed in Chapter 23 of
O'Reilly's 'Practical UNIX and Internet Security'. what we need is a
comprehensive list of functions, substitutions and guidelines to to
distribute to programmers. Anyone maintain such a list, or a list of
SUID programming guidelines?
Commercial products such as CodeCenter, or Pruify also
(supposedly) can help you catch buffer overflows. Anyone have opinions
about these? There's also Brian Marick's GCT (Generic Coverage Tool)
(ftp://ftp.cs.uiuc.edu/pub/misc/testing/) that's supposed to do similar
things, but has the advantage that it's distributed under the terms of
the GPL.

2. 'hmm. what if you change the compiler?'
C compilers could be modified to do bounds checking, and/or
problem functions could be made to complain to the user at compile time.
One implementation of bounds checking into C was done by Richard Jones
and Paul Kelly at Imperial College in July 1995.
(http://www-ala.doc.ic.ac.uk/~phjk/BoundsChecking.html)
Their patches to gcc are available in source and binary form
(ftp://dse.doc.ic.ac.uk/pub/misc/bcc/) for Linux, HPUX and SunOS &
Solaris. After such modifications to the compiler, the resulting code
is slower (which makes sense, because it now has to do a lot more to
look after itself) Furthermore, I can see the coming holy wars/flame
wars if the bcc patches were adopted widely, "C is supposed to be
simple, flexible and fast, it's not SUPPOSED to do bounds checking" (see
the "at the risk of another flamefest.." thread from BUGTRAQ, summer '96
(http://geek-girl.com/bugtraq/1996_3/index.html#60). IMHO, we want the
reliability and security if bounds checking in, say, ADA, but we don't
want to transform C into ADA! :) Can we simply write off these type of
patches/additions to C and its compilers as "incorrect/bad ideas"?

3. 'ok, what about the CPU/OS kernel stack exec permission?'
What about stopping the buffer overflow problem at the kernel
level? This might mean that you wouldn't have to inspect thousands of
lines of code, rebuild gcc, or recompile anything except the kernel.
Sounds nice, doesn't it.. well...
This has been a favorite one lately on BUGTRAQ and has come up a
few times on the linux-kernel mailing list. Solar Designer's recent
patches to the Linux kernel to remove stack exec permission, posted to
this list earlier this month, raised some interesting questions about
the buffer overflow problem, and how it can be implemented into an OS,
as well and the problems and dangers of doing this. In terms of Linux,
this type of patch has the danger of breaking things that use
"trampoline functions"(gcc & glibc), high level lisp interpreters,
objective C. Furthermore, returning from a signal requires an
executable stack (in Linux, anyways).. Workarounds for these problems
introduce new problems (buffer overflows in signal handlers?) and may
not be a suitable solution? I am assuming there are similar problems in
implementing this under other operating systems?

If BUGTRAQ readers are sick of discussing this, drop me some mail..

--
-Nate Smith <nate@millcomm.com> | http://millcomm.com/~nate/