Re: Unexecutable Stack / Buffer Overflow Exploits...

Steve VanDevender (stevev@efn.org)
Thu, 30 Dec 1999 17:58:09 -0800 (PST)


Theodore Y. Ts'o writes:
> From: Steve VanDevender <stevev@efn.org>
> Date: Thu, 30 Dec 1999 16:26:02 -0800 (PST)
>
> Many of the stack-smashing exploits I've seen pad the exploit
> code with a large number of no-op instructions; the return then
> has to point only somewhere into the no-op padding rather than
> directly at the useful part of the exploit code. Making a
> successful exploit in those cases takes less detailed knowledge
> and a lot fewer attempts before finding a return address that
> works, and it works in many more cases since the frame that gets
> smashed can be located over a much larger range of addresses.
>
> How much is a "large" number of no-op's? 4k? 8k? Usually it's a lot
> less than that; a few hundred no-op's at most. Remember, you actually
> have to send that many bytes down the network connection, and there may
> be other things (such as the maximum UDP packet size) which may limit
> how big you can make your "no-op runway".

Exploits using as much as 8K or more of no-op padding do exist.
For TCP-based network services the size of the input can be
arbitrarily large, and most remote exploits involve TCP-based
services anyway. That size of padding in cooked input or
command-line arguments is also common in non-network exploits of
setuid programs with buffer overruns.

> In any case, I suspect that if something randomly added some random
> value between 0 and 128k to the stack pointer at startup time, it would
> also go a fairly long way towards thwarting overrun attacks --- but make
> no mistake, it's still only papering over the problem.

If the stack isn't executable to begin with (and, for even higher
security, if the data segment wasn't executable either) this
would be more than just papering over the problem.

So far all you've suggested are kludges far worse than the
non-executable stack that offer significantly less protection. I
understand the objections to a non-executable stack, but I have
yet to see any arguments that address these two points:

1. Most buffer overrun exploits are simple stack smashes that
would be prevented by a nonexecutable stack. Arguing that this
would provide no real protection because it will force crackers
to develop on other methods of attack is bogus, because you could
make the same argument for almost any other built-in OS security
protection, i.e. restricting file permissions forces crackers to
find ways to gain the privileges needed to write to the files
they want, so restricting file permissions is only a temporary
solution too by that logic. The point is that something that was
available and easily exploitable to bypass security is no longer
available.

2. The overwhelming majority of programs on most systems do not
need to execute code in their stack segments as part of normal
operation. In my experience the use of trampolines and other
such tricks is exceedingly rare, especially compared to the
number of exploitable binaries I've had to patch or disable (and
still patch or disable when found even on the systems that have
non-executable stacks). I have four gigabytes of software each
on two Solaris systems including Sun-distributed,
vendor-distributed, and locally-compiled C and C++ code compiled
with gcc and the Sun compilers, not one item of which has been
reported as broken in the months since we turned on
noexec_user_stack.

I think the only argument with some validity is that on
architectures that do not allow pages to be marked non-executable
the code to accomplish non-executable stack or data pages is
messy or impossible. Unfortunately i386 is one of those
architectures, although it has been accomplished with a little
i386 segment trickery.

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/