0

I have this attempt to switch to a different stack by setting %rbp and %rsp:

#include <stdlib.h>
#include <stdio.h>


void* main_rbp = NULL;
void* main_rsp = NULL;


int run_stack() {
    int one = 1;
    printf("Hello from my new stack!\n");  // optimized to puts
    printf("crashes here but not when run with gdb\n"); // optimized to puts
    printf("1 = %d\n", one);
    return 0;
}


int main() {
    void* memory_block = malloc(1025);
    void* new_stack = memory_block + 1024;  // stack grows backwards, so start from end

    // save real stack pointers
    __asm__("movq %rbp, main_rbp(%rip)\n\t"
            "movq %rsp, main_rsp(%rip)\n\t");

    // set stack pointers to new_stack
    __asm__("movq -8(%rbp), %rsp\n\t"
            "movq -8(%rbp), %rbp\n\t");

    run_stack();

    // restore real stack pointers
    __asm__("movq main_rbp(%rip), %rbp\n\t"
            "movq main_rsp(%rip), %rsp\n\t");

    free(memory_block);
    printf("Still alive!\n");
    return 0;
}

And it segfaults:

$ ./main
Hello from my new stack!
crashes here but not when run with gdb
segmentation fault (core dumped) (or what it is in english)

But when I step through the same executable in gdb with pwndbg, everything (code flow, stack, registers) looks exactly as expected.

How can I track this issue down?

gdb output:

pwndbg> run
Starting program: ...../main 
Hello from my new stack!
crashes here but not when run with gdb
main_rbp: 0x7fffffffde20
main_rsp: 0x7fffffffde10
1 = 1
Still alive!
[Inferior 1 (process 22609) exited normally]
ssmid
  • 350
  • 2
  • 12
  • 1
    Have you tried `set disable-randomization off` in gdb? – ks1322 Sep 18 '21 at 17:28
  • Thank you! That's been the issue. – ssmid Sep 18 '21 at 18:11
  • To be remotely safe, that inline asm should be using Extended asm with `"memory"` clobbers. (Recent GCC, like since GCC7, does that implicitly for non-empty Basic `asm` statements, but that's just a workaround for naive code like this. Never use Basic Asm statements inside a non-`naked` function.) Also note that `%rbp` will only be set up as a frame pointer if you used `-fno-omit-frame-pointer` (which will be the case with the `-O0` default, but not at `-O2`). Also use `"r"` inputs for your allocations, not dead-reckoning of where GCC happens to store locals! – Peter Cordes Sep 19 '21 at 04:12
  • Anyway, single-step the actual asm, like with `layout asm` or `layout reg`, and watch register values change. – Peter Cordes Sep 19 '21 at 04:12
  • So where was this crashing, anyway? `void* memory_block` should be giving you 16-byte aligned memory, which is correct before a `call`, *if* the compiler doesn't move RSP after the `asm` statement before the call. – Peter Cordes Sep 19 '21 at 04:16
  • The problem was a simple buffer overflow. I didn't expect a short printf() call to overflow 1kB of stack memory. – ssmid Sep 22 '21 at 11:47

0 Answers0