1

I am writing the following code that will be able to change the stack of function call. but it always runs into segfault on printf. I debugged the code with assembly, the stack was successfully switched. it is the printf statement that created the segfault and not sure the reason. anybody has any clue what direction i should look into more?

Thanks.

char stack[4000000*4]; 

void foo(int ad) {
    int i = 100;
    int sum = i*i + ad;
    printf("stack changed to %X\n", stack);
}

/* in this example, foo (and its decendents) live on a new stack */
void change_stack(void *newstack) {
    void *ctx[5]; // Jump buffer for setjmp/longjmp.
    if (0 == __builtin_longjmp(ctx)) {
        ctx[2] = newstack; // switch stack  
        __builtin_longjmp(ctx, 1);/* here stack is switched */
    } else {
    /* now live on new stack, can we pass parameters now ? */
    int ad = 20;
    foo(ad);
    }
}

int main (int argc, char** argv)
{
  int i = 10;
  change_stack(stack);
  printf("return, %d\n", i);
  return 0;
}
Mat
  • 202,337
  • 40
  • 393
  • 406

2 Answers2

2

You switch stacks without copying the contents of the old one. When change_stack returns, the results are undefined (it may, for example, jump to address NULL, causing a segfault). Also, things like local variables will also be undefined.

Also, (assuming we're talking x86 here), the stack pointer is decremented on pushes. Since the new stack pointer you assigned is the base (i.e. lowest) address of your stack array, any push will decrease the pointer outside of this array, also possibly resulting in a segfault.

Drew McGowen
  • 11,471
  • 1
  • 31
  • 57
  • Thanks for your response. Yes, found out the same time that segfault comes from the reason in your second note. I need to use the highest address. For you first note, it is fine as the variable are accessed through frame pointer. – Yonghong Yan Jul 24 '13 at 03:59
  • Your latter point is correct in that variables are access through the frame pointer. However, the frame is stored on the stack, so the frame pointer still refers to the old stack space. – Drew McGowen Jul 24 '13 at 13:16
1

To anyone who still wants to play with the stack and also encountered SIGSEGV in printf, here is an important point:

You can find one of the subroutines of printf, __GI___tcgetattr under /path-to-glibc/sysdeps/unix/sysv/linux/tcgetattr.c. There is one instrution in it:

movdqa (%rsp),%xmm0

And according to this answer, it reads 16-byte align memory from source address. So you should keep the address of %rsp at least 16-byte address align when you switch the stack, otherwise you will get a SIGSEGV.

Dharman
  • 30,962
  • 25
  • 85
  • 135
yhdang
  • 169
  • 8