> Based on Ted's description of what you'd have to do to get around a
> non-executable stack: Every C program that has a local variable (virtually
> all of them) has a stack, where only programs that call other programs
> have a call to execv, so right there it is harder to implement an attack
> on a non-executable stack system.

> It's probably also a little harder to determine where in memory the exec
> call is, since you don't have a handy register (like the stack pointer) to
> tell you where it is.  So there again, it's still harder.  The real
> question is to what degree. I don't have the answer to that, but in my
> mind, it doesn't really matter, as long as there's something to be gained,
> no matter how small.  I have yet to see anyone describe what would be LOST
> by implementing this.

>From what I can tell, this method of getting around the non-executable stack
is not the only one.  I can't offer many details on other methods of getting
around a non-executable stack; I'm not that knowledgable.  I spent a little
time last night looking into the concept of buffer overrun vulnerabilities,
and found this in the documentation of a buffer-overflow attack detection
and prevention system at URL
http://www.cse.ogi.edu/DISC/projects/immunix/StackGuard/usenixsc98_html/pape
r.html:

        In addition to the above vulnerabilities, making the stack non-executable
fails to address the problem of buffer  overflow attacks that do not place
attack code on the stack. The attacker may inject the attack code into a
heap-   allocated or statically allocated buffer, and simply re-point a
function return address or function pointer to point to         the attack code.

I'm not sure how the attacker would manage to inject attack code into
non-stack buffers.

I do agree that making the stack non-executable would cause problems for
attackers, but it seems to be a temporary solution, and avoids the real
security hole:  The Buffer Overflow vulnerabilities themselves.  It comes
down to the fact that if your program is vulnerable to buffer overrun
attacks, you may be comprimising the security of the system.

>
> Programmers who know how to write secure code generally do.  It's those
> who don't that we have to worry about.  As I've already said earlier in
> this thread, no system administrator has time to analyze every line of
> code that gets run on their system, even if they have the ACCESS and the
> KNOWLEDGE to do so, which is by far the minority of cases.  Anti-stack
> smashing may not solve the problem, but it DOES HELP protect us from bad
> code that we are running (often because we have no choice).  Therefore it
> should be included in the kernel, unless other compelling reasons dictate
> otherwise.  I am not aware of any other arguments.
>

I'm not inclined to believe that programmers who know how to write secure
code always do so.  The programmers we are worrying about are good enough to
create applications that are intended to run suid root, and are accepted by
major linux distributions.  Programs like nfsd, sendmail, cron, klogd...
Programs that are known to be potential security problems, and have been
written or at least reviewed by security-conscious programmers.  These
programmers know how to write secure code - yet buffer overruns exist and
continue to be found, and fixed.

As for advantages of executable stacks, I've done a bit of looking around,
and found a couple reasons why it exists (These reasons found on the same
page as the discussion of how to get around non-executable stacks above):

-gcc uses executable stacks for function trampolines for nested functions.
-Linux uses executable user stacks for signal handling.
-Functional programming languages, and some other programs, rely on
executable stacks for run-time code generation.

As for the first one, I found this in a README for a set of patches to make
the stack non-executable in linux (http://www.openwall.com/linux/README):
    Q: What does GCC use trampolines for?
    A: Trampolines are needed to fully support one of the GNU C extensions,
    nested functions.  When a nested function is called from outside of the
    one it was declared in (that is, via a function pointer), something
needs
    to provide the stack frame.  The bad thing is that GCC puts trampolines
    onto the stack (as they're generated at runtime).

Regarding the second reason - This might be able to be done without using an
executable stack.  I don't know much about why this is done this way.

The third one is the biggest reason I see, as I've worked in functional
programming languages before.  Run-time code generation is important, and
integral to these programming languages.

Anyways, there are some reasons why executable stacks are a good thing...and
patches to the kernel exist that make the stack non-executable, although it
seems that some stuff may not quite work right afterwards.

Sheesh.  More rambling.  At least I'm not just arguing the use of an analogy
now.

-Jamie


**********************************************************
To unsubscribe from this list, send mail to
[EMAIL PROTECTED] with the following text in the
*body* (*not* the subject line) of the letter:
unsubscribe gnhlug
**********************************************************

Reply via email to