1

I am working on this c program. I am compiling it with gcc on a 64 bits x64 linux:

#include <stdio.h>

char buffer[]={0x90,0x90,0xC3};

int main(int argc, char *argv[])
{
    void (*fct)();
    fct=buffer;
    fct();
    return 0;
}

0x90 opcode is NOP

0xC3 opcode is RET

I want to know what i should do in order to run this program. I get a segfault when running it...

Thanks

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Bob5421
  • 7,757
  • 14
  • 81
  • 175
  • 1
    The `.data` section is probably not executable. Use `const char buffer` to put it in the `.rodata` section, which is (because it's linked as part of the text segment). – Peter Cordes Sep 15 '18 at 10:07
  • thanks but it does not work – Bob5421 Sep 16 '18 at 11:04
  • `const char buffer[] = {...};` works for me with or without optimization: https://godbolt.org/z/0lMuL9. I ran it on my desktop and it exited without faulting. What did you do differently that made it not work? – Peter Cordes Sep 16 '18 at 19:47
  • Update: more recent `ld` versions put `.rodata` in non-executable pages, presumably to reduce exposure of data as ROP / Spectre gadgets. – Peter Cordes May 17 '20 at 14:50

1 Answers1

3

TL;DR Compile with -z execstack to enable Linux's read-implies-exec feature for your executable. Despite the name, it applies to all pages, not just the stack.


The program is faulting because the buffer symbol goes into the .data section that in turns goes, along with other sections, into an ELF segment mapped Read-write but not executable.

To make the buffer executable the best course of action would be to make a new ELF segment with flags RWE and assign it a new section, then tell GCC to put buffer in this new section.
This could be done, in principle with the following linker script:

PHDRS
{
        MYSEG PT_LOAD FLAGS (7);
}
SECTIONS
{
        MYSECT : { *(MYSECT) } : MYSEG
}

, changing the source:

#include <stdio.h>

char buffer[] __attribute__ ((section ("MYSECT"))) ={0x90,0x90,0xC3};

int main(int argc, char *argv[])
{
    void (*fct)();
    fct=buffer;
    fct();
    return 0;
}

and the compiling passing the -T switch to GCC.

But this won't work.
GCC uses a default linker script based on the command line and the -T switch replace it entirely.
It's possible to get the script used by GCC with -Wl,-verbose and update it.

If we split the compilation and the linking by first invoking GCC with -c and then LD, we'd get only one segment because that's what we put in the linker script - thereby defeating all our efforts to make only buffer the only executable data.


With -z execstack we actually only tell GCC to use a linker script that sets the GNU_STACK ELF segment RWE.
This is a marker segment (size and lma are zero) used by the loader to setup the correct permissions for the stack pages.
But in truth it is used as a compatibility switch - when the stack is set as executable the loader will set all the writable pages as executable.

If you are playing with shellcodes -z execstack will make it easy, however it exposes your application to a boatload of attacks, but I guess this is what you needed in the first place.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Margaret Bloom
  • 41,768
  • 5
  • 78
  • 124
  • More about `-zexecstack` and the Linux `READ_IMPLIES_EXEC` "execution domain" it enables: [Unexpected exec permission from mmap when assembly files included in the project](https://stackoverflow.com/q/58260465) – Peter Cordes Oct 15 '20 at 07:48