lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Thu, 14 Aug 2003 01:03:17 +0200
From: Andreas Beck <becka@...-duesseldorf.de>
To: bugtraq@...urityfocus.com
Subject: Re: Buffer overflow prevention


"Jonathan A. Zdziarski" <jonathan@...workdweebs.com> wrote:
> I think this is overkill and will probably cause your applications to
> run much slower than they already do.

Ack. Sacrificing a register is probably pretty bad for x86.

I see more problems, though. The usual memory layout is to have 
code and fixed size data somewhere at the start of the virtual address
space, then above that the heap and the stack at the end.

This allows to let the heap top grow towards the stack bottom, allowing 
for maximum usage of the virtual address space which is small enough 
on x86 anyway (4GB isn't much for some apps ...)

Having another thing to place leaves the question of where to place
that without getting in the way for both common cases of apps with high
stack usage or high heap usage. 

And please do not argue for using a segment of its own. 
That causes really evil headaches when handling pointers.


> I don't see why one couldn't simply put the variable information 
> *after* the rest of the stack information, instead of before, 

Because that is not how C (and other languages that use its calling
convetion) works. The point is, that you can open subscopes anywhere
like this:

int some_function(int some_parm) {
	int some_var;
	...
	{
		int some_local_var;
	}
}

Using the usual layout that looks a bit like this:

some_parm
ret-address
some-locally-saved-regs
some_var
some_local_var

while inside the inner brackets, and the same just without the last line
while outside.

This is easy to implement and partially even supported by the CPU design. 
It is hard however to keep the ret address below anything else, as you 
would have to continuously copy it around.

AFAIK one could configure the stack to walk up instead of down, but that 
would pose a similar problem WRT the traditional memory layout and 
stuff like the traditional brk()/sbrk().


Moreover it just helps in a few specific cases, as do many other
approaches.

An increasingly popular problem are format string and stack smashing
attacks. 

Especially format string attacks are often capable to write to any
byte in memory. This way any function pointer that is called later
is at risk - no matter what you do to protect yourself using memory
separation techniques.

Of course the problem might be mitigated severely, as you cannot 
just download the shellcode, if all the writeable areas are not
executable anymore, but that just moves the challenge to find 
some clever way to abuse functions within the original code.

I have no doubt people will find a way - unicode exploits exist
as do exploits that can only use a specific subset of characters.


> and have the kernel zero out the next stack frame before it gets written 
> to (although this may cause some performance problems in itself).

Highly recursive programs might not be amused. Try running a program
that extensively uses malloc with efence for a taste of what happens.

A simple thing like a function call should very probably not cause the
System to fiddle with MMU tables ... hmm - or what did you mean with
zeroing out?


> This would prevent a buffer overflow from A) overwriting SS:ESP and 
> B) overflowing code onto the next stackframe.

Basically a stack canary should do the same.


So I agree with some others here: Fix the problem, not the symptom.

And the problem is, that buffers are overflowed, because the APIs
for string handling are ... umm ... let's say ... suboptimal.

A common length-checking set of functions along the lines of the
C-library str* and sprintf functions plus a few others would already 
help a lot. Not that these do not exist ... the problem is to
teach people to exclusively use them.


In a similar way, automatic overflow checking (e.g. selectable by a
compiler pragma so we don't loose performance, when it is not critical 
anyway) would prevent quite some of the integer-overflow problems we 
are seeing.


CU, Andy, waiting for another rout of out-of-office junk.

-- 
= Andreas Beck  |  Email :  <becka@...-duesseldorf.de> =


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ