INSIGHTS, NEWS & DISCOVERIES
FROM IOACTIVE RESEARCHERS

Wednesday, November 27, 2013

A Short Tale About executable_stack in elf_read_implies_exec() in the Linux Kernel

by Alejandro Hernández @nitr0usmx 

This is a short and basic analysis I did when I was uncertain about code execution in the data memory segment. Later on, I describe what’s happening in the kernel side as well as what seems to be a small logic bug.

I’m not a kernel hacker/developer/ninja; I’m just a Linux user trying to figure out the reason of this behavior by looking in key places such as the ELF loader and other related functions. So, if you see any mistakes or you realize that I approached this in a wrong way, please let me know, I’d really appreciate that.

This article also could be useful for anyone starting in shellcoding since they might think their code is wrong when, in reality, there are other things around to take care of in order to test the functionality of their shellcodes or any other kind of code.


USER-LAND: Why is it possible to execute code in the data segment if it doesn’t have the PF_EXEC enabled?

A couple of weeks ago I was reading an article (in Spanish) about shellcodes creation in Linux x64. For demonstration purposes I’ll use this 64-bit execve(“/bin/sh”) shellcode: 

#include <unistd.h>

char shellcode[] =
"\x48\x31\xd2\x48\x31\xf6\x48\xbf"
"\x2f\x62\x69\x6e\x2f\x73\x68\x11"
"\x48\xc1\xe7\x08\x48\xc1\xef\x08"
"\x57\x48\x89\xe7\x48\xb8\x3b\x11"
"\x11\x11\x11\x11\x11\x11\x48\xc1"
"\xe0\x38\x48\xc1\xe8\x38\x0f\x05";

int main(int argc, char ** argv) {
        void (*fp)();
        fp = (void(*)())shellcode;
        (void)(*fp)();

        return 0;
}

The author suggests the following for the proper execution of the shellcodes:
We compile and with the execstack utility we specify that the stack region used in the binary will be executable...”.

Immediately, I thought it was wrong because of the code to be executed would be placed in the ‘shellcode’ symbol in the .data section within the ELF file, which, in turn, would be in the data memory segment, not in the stack segment at runtime. For some reason, when trying to execute it without enabling the executable stack bit, it failed, and the opposite when it was enabled:

 

According to the execstack’s man-page:
“… ELF binaries and shared libraries now can be marked as requiring executable stack or not requiring it… This marking is done through the p_flags field in the PT_GNU_STACK program header entry… The marking is done automatically by recent GCC versions”.

It only modifies one bit adding the PF_EXEC flag to the PT_GNU_STACK program header. It also can be done by modifying the binary with an ELF editor such as HTEditor or at linking time by passing the argument ‘-z execstack’ to gcc. 
The change can be seen simply observing the flags RWE (Read, Write, Execution) using the readelf utility. In our case, only the ‘E’ flag was added to the stack memory segment:
 
The first loadable segment in both binaries, with the ‘E’ flag enabled, is where the code itself resides (the .text section) and the second one is where all our data resides. It’s also possible to map which bytes from each section correspond to which memory segments (remember, at runtime, the sections are not taken into account, only the program headers) using ‘readelf -l shellcode’.

So far, everything makes sense to me, but, wait a minute, the shellcode, or any other variable declared outside main(), is not supposed to be in the stack right? Instead, it should be placed in the section where the initialized data resides (as far as I know it’s normally in .data or .rodata). Let’s see where exactly it is by showing the symbol table and the corresponding section of each symbol (if it applies):


It’s pretty clear that our shellcode will be located at the memory address 0x00600840 in runtime and that the bytes reside in the .data section. The same result for the other binary, ‘shellcode_execstack’.

By default, the data memory segment doesn’t have the PF_EXEC flag enabled in its program header, that’s why it’s not possible to jump and execute code in that segment at runtime (Segmentation Fault), but: when the stack is executable, why is it also possible to execute code in the data segment if it doesn’t have that flag enabled? 

 
Is it a normal behavior or it’s a bug in the dynamic linker or kernel that doesn’t take into account that flag when loading ELFs? So, to take the dynamic linker out of the game, my fellow Ilja van Sprundel gave me the idea to compile with -static to create a standalone executable. A static binary doesn’t pass through the dynamic linker, instead, it’s loaded directly by the kernel (as far as I know). The same result was obtained with this one, so this result pointed directly to the kernel.

I tested this in a 2.6 kernel (x86_64) and in a 3.2 kernel (i686), and I got the same behavior in both.


KERNEL-LAND: Is that a bug in elf_read_implies_exec()?

Now, for the interesting part, what is really happening in the kernel side? I went straight to load_elf_binary()in linux-2.6.32.61/fs/binfmt_elf.c and found that the program header table is parsed to find the stack segment so as to set the executable_stack variable correctly:

     int executable_stack = EXSTACK_DEFAULT;
...
     elf_ppnt = elf_phdata;
     for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++)
             if (elf_ppnt->p_type == PT_GNU_STACK) {
                     if (elf_ppnt->p_flags & PF_X)
                             executable_stack = EXSTACK_ENABLE_X;

                     else
                             executable_stack = EXSTACK_DISABLE_X;
                     break;
             }


Keep in mind that only those three constants about executable stack are defined in the kernel (linux-2.6.32.61/include/linux/binfmts.h):

/* Stack area protections */
#define EXSTACK_DEFAULT    0  /* Whatever the arch defaults to */
#define EXSTACK_DISABLE_X  1  /* Disable executable stacks */
#define EXSTACK_ENABLE_X   2  /* Enable executable stacks */


Later on, the process’ personality is updated as follows:

     /* Do this immediately, since STACK_TOP as used in setup_arg_pages may depend on the personality.  */
     SET_PERSONALITY(loc->elf_ex);
     if (elf_read_implies_exec(loc->elf_ex, executable_stack))
             current->personality |= READ_IMPLIES_EXEC;


     if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
             current->flags |= PF_RANDOMIZE;
...


elf_read_implies_exec() is a macro in linux-2.6.32.61/arch/x86/include/asm/elf.h:

/*
 * An executable for which elf_read_implies_exec() returns TRUE 

 * will have the READ_IMPLIES_EXEC personality flag set automatically.
 */
#define elf_read_implies_exec(ex, executable_stack)     \
        (executable_stack != EXSTACK_DISABLE_X)


In our case, having an ELF binary with the PF_EXEC flag enabled in the PT_GNU_STACK program header, that macro will return TRUE since EXSTACK_ENABLE_X != EXSTACK_DISABLE_X, thus, our process’ personality will have READ_IMPLIES_EXEC flag. This constant, READ_IMPLIES_EXEC, is checked in some memory related functions such as in mmap.c, mprotect.c and nommu.c (all in linux-2.6.32.61/mm/). For instance, when creating the VMAs (Virtual Memory Areas) by the do_mmap_pgoff() function in mmap.c, it verifies the personality so it can add the PROT_EXEC (execution allowed) to the memory segments [1]:

     /*
      * Does the application expect PROT_READ to imply PROT_EXEC?
      *
      * (the exception is when the underlying filesystem is noexec
      *  mounted, in which case we dont add PROT_EXEC.)
      */
     if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
             if (!(file && (file->f_path.mnt->mnt_flags & MNT_NOEXEC)))
                     prot |= PROT_EXEC;


And basically, that’s the reason of why code in the data segment can be executed when the stack is executable.

On the other hand, I had an idea: to delete the PT_GNU_STACK program header by changing its corresponding program header type to any other random value. Doing that, executable_stack would remain EXSTACK_DEFAULT when compared in elf_read_implies_exec(), which would return TRUE, right? Let’s see:


The program header type was modified from 0x6474e551 (PT_GNU_STACK) to 0xfee1dead, and note that the second LOAD (data segment, where our code to be executed is) doesn’t have the ‘E’xecutable flag enabled: 

 
The code was executed even when the execution flag is not enabled in the program header that holds it. I think it’s a logic bug in elf_read_implies_exec() because one can simply delete the PT_GNU_STACK header as to set executable_stack = EXSTACK_DEFAULT, making elf_read_implies_exec() to return TRUE. Instead comparing against EXSTACK_DISABLE_X, it should return TRUE only if executable_stack is EXSTACK_ENABLE_X:

#define elf_read_implies_exec(ex, executable_stack)     \
        (executable_stack == EXSTACK_ENABLE_X)


Anyway, perhaps that’s the normal behavior of the Linux kernel for some compatibility issues or something else, but isn’t it weird that making the stack executable or deleting the PT_GNU_STACK header all the memory segments are loaded with execution permissions even when the PF_EXEC flag is not set?

What do you think?


Side notes:
-       Kernel developers pass loc->elf_ex and never use it in:
#define elf_read_implies_exec(ex, executable_stack) (executable_stack != EXSTACK_DISABLE_X)

-       Two constants are defined but never used in the whole kernel code:
#define INTERPRETER_NONE 0
#define INTERPRETER_ELF  2


Finally, I’d like to thank my collegues Ilja van Sprundel and Diego Bauche Madero for giving me some ideas.


Thanks for reading.

References:
[1] “Understanding the Linux Virtual Memory Manager”. Mel Gorman.
Chapter 4 - Process Address Space.


No comments:

Post a Comment