Messages in this thread | | | Date | Tue, 3 Jun 1997 22:12:04 -0400 (EDT) | From | "Richard B. Johnson" <> | Subject | Re: Non-Executable Stack Patch |
| |
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. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
| |