0

In a C++ Arduino library, can we modify the call stack from inside a function by intentionally decrementing a pointer to a stack variable so that it's out of range? Like this:

void FooBar()
{
  char a;
  char *ptr = &a;
  ptr -= 4;
  // Can we edit the call stack with ptr now?
}

Can we use this to, for example, change what function is "calling" FooBar() by replacing the function pointer of the calling function on the call stack to another function? Or can we change the values of function variables in the calling function in mischievous fashion?

  • 1
    Yes, you can. Learn the ABI first so you know what is where. gcc.gnu.org/wiki/avr-gcc#Frame_Layout However I wouldn't recommend doing so - nasty things can happen if you futz with the stack frame. – Majenko Jan 16 at 22:58
  • Yes, you can, but it won't work. The compiler can do many optimizations, so it is very doubtful that it will work. When you are serious about writing software, then you should never do such things. Stay far away from things that are bound to go wrong. Every software engineer that sees your piece of code is now feeling very uncomfortable and is banging his/her head against the wall screaming out loud: no, no, no. – Jot Jan 17 at 8:21
  • I recommend you to generate an .lst file and see the assembly – Juraj Jan 17 at 8:44
1

I am answering in the context of the AVR calling conventions, as they are the only ones I know well enough to be able to answer here.

Can we use this to, for example, change what function is "calling" FooBar() by replacing the function pointer of the calling function on the call stack to another function?

That will probably be impossible in C++. Let's say you have the following call chain: main()f()FooBar(). In the body of FooBar(), the stack will look like this (oldest stuff at top):

return address from f() to main()
registers saved by the f() prologue
return address from FooBar() to f()
registers saved by the FooBar() prologue

Getting the stack pointer is easy. No need to declare a dummy variable, just:

char *stack_pointer = (char *) SP;

Now, to change the required return address, you need to skip over the registers saved by the FooBar() prologue. And this is the big problem: you do not know how many registers were saved there. Function prologues are written by the compiler, and whatever they save depends on how many registers are needed within the function, which in turn depends on the complexity of that function. Even minor changes to the function can modify the number of registers its prologue saves.

The only solution to this problem I can imagine is to forego the compiler-generated prologue and write FooBar() in assembly. If you wish to do it within a C++ file, you can attach the "naked" attribute to the function and write its body using inline assembly.

Or can we change the values of function variables in the calling function in mischievous fashion?

No need to tamper with the stack for this. The compiler strives to store as many local variable as possible in CPU registers rather than the stack. The caller's local variables are most likely still in those registers and you can modify them at will (in assembly). That's why you have this register-saving prologue and register-restoring epilogue in the first place. Indeed, if you make the function "naked" and don't do the saving/restoring yourself, you will very likely end up corrupting the caller's locals.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.