Re: Non-Executable Stack Patch

Richard B. Johnson (root@analogic.com)
Tue, 3 Jun 1997 22:12:04 -0400 (EDT)


On Tue, 3 Jun 1997, David S. Miller wrote:

> Date: Wed, 4 Jun 1997 01:58:40 +0300 (IDT)
> From: Andi Gutmans <andi@vipe.technion.ac.il>
>
> I think it's really ashame that the non-executable stack patch
> doesn't seem to be making it's way into the kernel as an option.

If you have been following the thread, you should have noted the reason
why the stack is executable. The 'C' runtime libraries use trampolines
to supply otherwise 'local' variables to functions called. This allows
the code to swiftly execute without the overhead of pushes, calls, and
leveling the stack. The trampoline is like an array built on the stack.
This array contains executable code. This code is executed. You can't
actually do this from ANSI 'C', but with assembly, you can do anything.
Therefore, those who write only in 'C' might not understand what is
being done. Basically the logic is:

char buffer[]={0x3c, 0x0f, 0x21, 0x2f, 0xc9};
|___ executable code
ret = (*buffer)(); execute the code.

The code may access 'local' variables, etc. This kind of construct
is used extensively in X. If the stack was not executable, you could
break a lot of code. Note that this buffer, containing code could
actually be an array of pointers to buffers, each containing a snippet
of code necessary to handle some small thing based upon a condition.
The result is a very powerful construct.

The fact that the stack is executable can be used by a sniper to
make a program execute something that was not intended. If a buffer,
allocated on the stack, was written with the necessary 'code' to
do something "bad", and the buffer was deliberately overwitten into
the procedure's return address, it is possible to execute that code.

For the normal user, this would not compromise the system, it would
just be an 'expensive' way to execute something. However, a SUID program
such as many 'system' utilities must be written to prevent such stack
overflow. Basically, you don't use 'gets()` to get input. You always
use some function call that checks the length of input data so you
don't overflow your buffers.

This is the correct way of preventing abuse. It doesn't matter what
a user writes to a buffer as long as it can't possibly be executed.

The source code is available for everything that takes user input. You
only have to look at the SUID programs like mail, your mail daemon, etc.
You can check for user input line-by-line and verify that it is impossible
to overflow any input buffers. Compile, install, and sleep soundly.

Cheers,
DJ
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Richard B. Johnson
Analogic Corporation
Email : rjohnson@analogic.com, johnson@analogic.com
Penguin : Linux version 2.1.42 on an i586 machine (66.15 BogoMips).
Warning : It's hard to stay on the trailing edge of technology.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-