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

6
  • 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). Commented Sep 15, 2018 at 10:07
  • thanks but it does not work Commented Sep 16, 2018 at 11:04
  • const char buffer[] = {...}; works for me with or without optimization: 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? Commented Sep 16, 2018 at 19:47
  • Update: more recent ld versions put .rodata in non-executable pages, presumably to reduce exposure of data as ROP / Spectre gadgets. Commented May 17, 2020 at 14:50
  • 1
    @nostromo: __attribute__((section(".text"))) can put an array in .text which gets linked into an executable mapping. Otherwise you'd have to mprotect it, since modern ld's default linker script avoids making anything executable if it doesn't have to be. Commented Apr 13, 2025 at 17:42

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.