0

I am trying to write a C program on Linux that jumps to a location that can be written by the program itself.

#include <stdio.h>
int main(int argc, char* argv[]) {
    char a[] = {0x41, 0x5c, 0x41, 0x5d, 0x41, 0x5e, 0x41, 0x5f, 0x0};
    __asm__("pop %%r12;"
            "jmp *%[a];"
            "pop %%r11;" : : [a] "r" (a) : );
    return 0;
}

Array a contains instruction pop %r12; pop %r13; pop %r14; pop %r15, and I hope to use the jmp instruction to jump to array a's address and execute the instructions.

However, this program raises segment fault when executing. I used gcc to compile my program and gdb to step through each instruction. What I find is that the program successfully jumps to array a's address, but before it can execute the first instruction, the it receives signal SIGSEGV.

Why is this happening? Does it mean that I cannot jump to a writable location? Is this a hardware limitation? (If so, how can I check whether my CPU supports this kind of jump? )

I am using a x86_64 CPU, and the program is compiled in 64-bit mode.

Eric Stdlib
  • 1,292
  • 1
  • 18
  • 32
  • 3
    By default the stack is mapped read+write but not execute. You want `gcc -zexecstack`. But I don't understand why you're popping whatever's on the stack before jumping, or including a `pop` *after* the jmp (which doesn't have any way to return). Normally you'd just cast it to a function pointer and call it, so the C compiler emits a `call` instruction. – Peter Cordes May 29 '19 at 03:41
  • The pop instructions are just random instructions (may be replaced by other instructions later). I think the `-zexecstack` solves my problem. – Eric Stdlib May 29 '19 at 04:22
  • Replaced later how? Not at runtime, because you don't have the address of that code. If you want to use `call` instead of `jmp` and have your machine code actually return, you should *not* use inline asm for this. You're clobbering the compiler's registers without telling it, and you inevitably clobber the red-zone where the compiler might have been keeping stuff below RSP. Cast to a function pointer. See the linked duplicate for the syntax for casting to a function pointer and dereferencing the result to get a return value. – Peter Cordes May 29 '19 at 04:36
  • 1
    Normally, the pages of your program's memory that are writable are set as non-executable, and those that are executable are set as non-writable. You can change protections for a region of memory by calling `mprotect(2)`. – Nate Eldredge May 29 '19 at 05:10

0 Answers0