[14656] in bugtraq
Re: Libsafe Protecting Critical Elements of Stacks
daemon@ATHENA.MIT.EDU (Crispin Cowan)
Tue Apr 25 20:53:39 2000
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="------------20B71EE59AFF94F881196776"
Message-Id: <39050BF9.B0C98C45@wirex.com>
Date: Tue, 25 Apr 2000 03:07:38 +0000
Reply-To: crispin@WIREX.COM
From: Crispin Cowan <crispin@WIREX.COM>
X-To: JEFF PFOHL <pfohl@NUCALF.PHYSICS.FSU.EDU>
To: BUGTRAQ@SECURITYFOCUS.COM
This is a multi-part message in MIME format.
--------------20B71EE59AFF94F881196776
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
JEFF PFOHL wrote:
> Does anyone know anything about this?
>
> http://www.bell-labs.com/org/11356/html/security.html
Solar Designer has posted his analysis to the Linux security-audit
mailing list
http://www2.merton.ox.ac.uk/~security/security-audit-200004/0069.html .
Perry Wagle (principle StackGuard developer, cc'd) has written an
analysis comparing StackGuard to libsafe (attached). The summary is as
follows:
* Use StackGuard where you can, because it is safer:
o Libsafe only wraps selected string library functions. Buffer
overflows affecting other library functions or user-written
loops will not be protected
o Libsafe attempts to wrap these functions by parsing the stack,
but it doesn't always succeed. In particular, libsafe depends
on the existance of the frame pointer, and fails when it isn't
present, as happens if the code was compiled with -fno_fp, or
if the optimizer removed the frame pointer.
* Use Libsafe where you cannot use StackGuard, i.e. for binary-only
applications.
My further comment on libsafe: the paper that the authors will be
presenting at USENIX in June presents two forms of defense ("library
intercept" and binary-rewrite (BRW)) and only the library intercept
appears to be embodied in the publicly available libsafe, which is why
libsafe only protects against overflows that use particular string
library functions.
The BRW method is a pseudo-compiler that can transform binaries into
"safe" programs by transforming the binary. It copies program onto the
heap, inserting checks as it goes. The copy-to-the-heap is to make
space for the additional checks. I really like the BRW method, and hope
it becomes available.
If my understanding is mistaken, and BRW is actually in the distributed
libsafe, please correct me.
Crispin
-----
Crispin Cowan, CTO, WireX Communications, Inc. http://wirex.com
Free Hardened Linux Distribution: http://immunix.org
JOBS! http://immunix.org/jobs.html
--------------20B71EE59AFF94F881196776
Content-Type: message/rfc822
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Return-Path: <wagle@cse.ogi.edu>
Delivered-To: crispin@wirex.com
Received: from church.cse.ogi.edu (cse.ogi.edu [129.95.20.2])
by mithra.wirex.com (Postfix) with ESMTP id 2C1EB3EC15
for <crispin@wirex.com>; Mon, 24 Apr 2000 18:56:56 -0700 (PDT)
Received: (from wagle@localhost)
by church.cse.ogi.edu (8.9.3/8.9.3) id SAA28838;
Mon, 24 Apr 2000 18:55:01 -0700 (PDT)
Date: Mon, 24 Apr 2000 18:55:01 -0700 (PDT)
From: Perry Wagle <wagle@cse.ogi.edu>
Message-Id: <200004250155.SAA28838@church.cse.ogi.edu>
To: crispin@wirex.com, wagle@cse.ogi.edu
Subject: Re: [Fwd: libsafe]
X-Mozilla-Status2: 00000000
Lucent Bell Labs has released "libsafe" to help prevent buffer overflow
attacks (http://www.newsalert.com/bin/story?StoryId=Cop6aWbKbyteXnZC).
Their web page is (http://www.bell-labs.com/org/11356/libsafe.html).
I downloaded the source. My assessment is that its a stack parser
with front ends for a few of the usual suspects for buffer overflows
(strcpy, strcat, getwd, gets, [vf]scanf, realpath, [v]sprintf). The
front ends (attempt to) check the bounds of the stack frame that the
buffer resides in.
Immunix decided years ago not to do stack parsers. GDB (the GNU
debugger) can't do it reliably in my experience on Linux/i386, why
would we be better? Mathematically, an executing program can parse
its own stack because part of the necessary information is encoded in
data on the stack, and part is hardcoded in the program instructions.
Parsing the stack is probably [undecidably?] hard for an external
observer [a particular instance of the compiler might produce
instruction streams with decidable stack behavior].
The flaws with LibSafe are (in no particular order):
(1) LibSafe assumes that the stack grows downward, and well as other
i386'sms. This is a repairable nitpick.
(2) LibSafe assumes that saved frame pointers are at the beginning of
each stack frame. This isn't always true. Optimizers can decide
not to save the frame pointer, and programmers can tell the
compiler not to save it. So, unlike StackGuard, LibSafe doesn't
necessarily protect each stack frame.
(3) Only calls to "strcpy, strcat, getwd, gets, [vf]scanf, realpath,
and [v]sprintf" are protected. Statistically, this is probably
good coverage, but the whole C paradigm is null terminated strings
and no array bounds checks, so its not as complete as StackGuard,
since these aren't the only routines that overflow buffers.
(4) They don't protect anything before the supposed location of the
frame pointer on the stack. In particular, saved registers and
adjacent autovars to the buffer. StackGuard is worse, it doesn't
even protect the saved frame pointer. Technically, StackGuard
could put canaries most anywhere on the stack that it wants; but
due to the nature of its "after the fact" detection, it seemed
prudent to put canaries as close to the protected data (the return
address "transfer of control" hook) as possible.
(5) LibSafe doesn't work if the application statically links the
lineup of usual suspects (listed above). It works by preloading
the stub replacements via ELF dynamic library loading.
(6) I think they exagerate the performance hit of StackGuard
(moderate?!?!), but that's not too unreasonable of them. I mean,
what *would* a objective threshold be?
Pluses are:
(1) When it works, LibSafe is proactive rather than reactive like
StackGuard. Buffer overflows are detected before they occur,
rather than afterward like StackGuard. This isn't that big a
point, given that StackGuard detects it pretty quickly -- and most
importantly before the transfer of control to the injected code.
(2) The LibSafe overflow exception handler is more complex (sends
email, etc) than my default StackGuard one. Which is more
comfortable to do since the buffer overflow is prevented and state
is (allegedly) not corrupt.
(3) When LibSafe works, it protects the saved frame pointer as well as
the return address. StackGuard only protects the return address.
Of course, neither protects the saved registers and the other
autovars.
(4) They don't require recompilation of the application, which beats
StackGuard for closed-source applications.
(5) Yet again, someone gets mileage out of an idea that I have first,
but decide is trivial. 8) 8(
They compare the performance to some unknown version of StackGuard,
and are faster. Well, sure, they protect less stuff.
Finally, according to the article:
Linux distributors Red Hat, Inc., Linux-Mandrake, Turobolinux and
Debian GNU/Linux are working with Bell Labs to incorporate Lucent
Libsafe into their software releases.
My conclusion is that I should use LibSafe to protect software that I
can't recompile, and StackGuard to protect that which I can. The only
advantage to combining the two (that I can see) is for protecting
(some of) the saved frame pointers.
-- Perry
--------------20B71EE59AFF94F881196776--