Nikita Kakuev Nikita Kakuev - 16 days ago 7
Linux Question

Stacks are executable even with `noexecstack`

I'm trying to protect my application against buffer overflow exploits. Among other things, I'm using non-executable stacks and link my binaries with the

noexecstack
flag (by passing
-Wl,-z,noexecstack
to gcc).

Everything seems fine -
readelf
confirms that
PT_GNU_STACK
specifies correct permissions:

$ readelf -l target | grep -A1 GNU_STACK
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 10


So does
execstack
:

$ execstack -q target
- target


There's only one problem. All my stacks are actually executable:

root@170ubuntu16p04-64smp-1:~# cat /proc/12878/task/*/maps | grep stack
7ffcac654000-7ffcac675000 rwxp 00000000 00:00 0 [stack]
7fe540e66000-7fe541666000 rwxp 00000000 00:00 0 [stack]
7fe540665000-7fe540e65000 rwxp 00000000 00:00 0 [stack]
7fe53b800000-7fe53c000000 rwxp 00000000 00:00 0 [stack]


I've trapped allocate_stack calls and examined protection flags. In theory, they should be initialized according to
PT_GNU_STACK
. But in my case, it seems like
PT_GNU_STACK
was ignored and
_dl_stack_flags
was initialized with default permissions.

Does anyone know what could have caused this? Everything seems correct, but stacks are still executable.

I'm using gcc 4.8.3 / glibc 2.11.

Answer

Olaf and Employed Russian pushed me in the right direction. A third-party shared object was poisoning my stacks.

But it wasn't linked to my main executable directly. Both ldd and lddtree weren't showing any libraries with RWE stacks, so I've decided to dig deeper and wrote a script that checked all shared objects currently mapped into a process memory:

#!/bin/bash

if [ -z "$1" ]; then
    echo "Usage: $0 <target>"
    exit 1;
fi

kav_pid=`pidof $1`
for so in `cat /proc/$kav_pid/task/*/maps | awk '/.so$/ {print $6}' | sort | uniq`; do
    stack_perms=`readelf -Wl $so | awk '/GNU_STACK/ {print $7}'`
    if [ -z "$stack_perms" ]; then
        echo "$so doesn't have PT_GNU_STACK"
    elif [ "$stack_perms" != "RW" ]; then
        echo "$so has unexpected permissions: $stack_perms"
    fi
done

And it worked! I found a library with RWE permissions:

$ ./find_execstack.sh target
/target/dir/lib64/lib3rdparty.so has unexpected permissions: RWE

To make sure that it was this library that poisoned my stacks, I opened my application with gdb and set a breakpoint in dlopen. And Bingo! Here are the permissions before dlopening lib3rdparty.so:

7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]

And here are they right after the dlopen:

7ffffffde000-7ffffffff000 rwxp 00000000 00:00 0                          [stack]

As it turned out, lib3rdparty.so was built using a different toolchain and that went unnoticed utill now.

Olaf, Employed Russian, thank you!