On 10/17/10 10:01, Ali Bahrami wrote:
I've had the same thought about having ld always generate
a PT_SUNWSTACK, and even sent some internal email yesterday
proposing it to my fellow linker alien. It's actually simpler
than what we do now, since we'd just remove the code that
checks the header flags against the ABI defaults before issuing
the header. It seems reasonable to me, and we'll see what others think.

   I had a few minutes today to try an experiment, and I'm afraid
the idea of having ld always generate a PT_SUNWSTACK is a non-starter.

The problem is that it overrides the behavior of 'set noexec_user_stack=1'
in /etc/system, and can therefore quietly allow programs that would
not previously been able to execute on the stack do so.

I used the following test program to play with this.

------------------------------------------------------------------
#include <stdio.h>
#include <strings.h>

/*
    Code bytes for

        static void f(void) { }

    obtained by compiling with 'cc -Kpic', and using dis to disassemble.

    f:                      55                 pushl  %ebp
    f+0x1:                  8b ec              movl   %esp,%ebp
    f+0x3:                  83 ec 04           subl   $0x4,%esp
    f+0x6:                  89 5d fc           movl   %ebx,-0x4(%ebp)
    f+0x9:                  8b 5d fc           movl   -0x4(%ebp),%ebx
    f+0xc:                  c9                 leave
    f+0xd:                  c3                 ret
    0x80509ee:              90                 nop
    0x80509ef:              90                 nop
*/
unsigned char fbuf[] = {
        0x55,
        0x8b, 0xec,
        0x83, 0xec, 0x04,
        0x89, 0x5d, 0xfc,
        0x8b, 0x5d, 0xfc,
        0xc9,
        0xc3,
        0x90,
        0x90
};

int
main(int argc, char **argv)
{
        double buf[(sizeof(fbuf) + 7) / 8];
        void (* fp)(void);

        bcopy((void *) fbuf, buf, sizeof(fbuf));
        fp = (void *) buf;
        (*fp)();
        printf("DONE\n");
        return (0);
}
------------------------------------------------------------------

I then put the following in /etc/system on my X86 system, and rebooted:

    set noexec_user_stack=1
    set noexec_user_stack_log=1

On my system:
    % cc main.c
    "main.c", line 44: warning: assignment type mismatch:
            pointer to function(void) returning void "=" pointer to void
    % ./a.out
    Segmentation Fault (core dumped)

This is what you'd expect: The a.out, and the IA32 ABI allow an executable
stack, but the kernel denies it due to noexec_user_stack. Running the same
executable on a system without the /etc/system setting, it works:

    % ./a.out
    DONE

Back on my system, let's give it a PT_SUNWSTACK, and disable the executable
stack:

    % cc -Kpic -M /usr/lib/ld/map.noexstk main.c
    "main.c", line 40: warning: assignment type mismatch:
            pointer to function(void) returning void "=" pointer to void
    % ./a.out
    Segmentation Fault (core dumped)

And using elfedit to modify the stack header, we can make this program
run to completion:

    % elfedit -e 'phdr:p_flags -or sunwstack x' a.out
    % ./a.out
    DONE

Note that we've still got noexec_user_stack set. Putting this all together,
it appears that exec() uses the following rules when setting up the stack
for an executable:

    1) Initialize stack protections to ABI default for platform
    2) If noexec_user_stack is set, remove the execute bit from
       the stack permissions.
    3) If the executable has a PT_SUNWSTACK header, replace the stack
       permissions with those given by the header.

So I'm imagining a system out there, in production, with noexec_user_stack set.
This system has a bunch of executables built with the ld defaults, and so, these
objects have no PT_SUNWSTACK. Two things happen:

    1) The system is upgraded, and has our new ld that always
       issues PT_SUNWSTACK.

    2) The executables are rebuilt on this new system.

The result is that programs on this production system that would previously
not have been allowed to execute code on the stack will now be allowed to do
so. And this will have happened happened without anyone thinking about the
security implications, or even being aware that they should. That's bad.

Until there's a consensus that Solaris should ignore the platform ABI,
I think we're back to the original assertion that the best you can do is
to always link with -M /usr/lib/ld/map.noexstk, and to set noexec_user_stack.

Since executables that need an executable stack are rare, another answer
is to always set noexec_user_stack, and to insist that programs that need
an executable stack must have a PT_SUNWSTACK that makes it so.

- Ali
_______________________________________________
opensolaris-discuss mailing list
opensolaris-discuss@opensolaris.org

Reply via email to