# Signal Handler and Stacks The goal is to take the following program, register the given signal handler for handling the case of floating point division by zero, and within the signal handler, write some code that skips the instruction in `main` that causes the floating point division error. ```c #include <signal.h> #include <stdio.h> #include <stdlib.h> void signal_handle(int signalno) { printf("OMG, I was slain!\n"); /* Step 4: Handle SIGFPE and change the stack*/ /* Do your tricks here * Your goal must be to change the stack frame of caller (main function) * such that you get to the line after "z=x/y"*/ /* next statement exit(1) has been commented. understand what happens, then remove the comment and then execute */ // exit(1); } int main(int argc, char *argv[]) { int x=5, y = 0, z=4; /* Step 1: Register signal handler first*/ // This will generate floating point exception z=x/y; printf("LOL, I live again !!!%d\n", z); return 0; } ``` We're asked to do this by creating a pointer to some value on the stack and adjusting it to point at the program counter, then modifying the program counter such that the offending instruction is skipped. The program counter is (for the sake of simplicity), a value stored on the stack containing the address of the next instruction to be executed. If we modify this value to contain the address of the instruction _following_ the line `z=x/y;`, we can avoid having it run again (which would cause the error to occur a second time, and so forth). ### Inspecting the Stack The instructions point out that, first of all, the parameter of the signal handler (the integer `signalno`) is a value that exists on the stack. Recalling that pointers are just the memory addresses that values live at, it's clear that a pointer to `signalno` is a memory address that resides within the stack. It follows that a pointer to any other value on the stack can be acquired by creating a pointer to `signalno` and modifying the pointer (adding to or subtracting from the memory address it contains) by the appropriate amount. The goal at present is to get a pointer to the program counter, which we know lives on the stack as well. All we need to do is figure out the correct amount to increase or decrease the memory address of `signalno` by in order to point to the program counter instead. We can begin looking for the correct amount to offset a pointer to `signalno` by via gdb. Compile your program with `gcc -o stack stack.c -m32 -g` and run it with gdb (`gdb stack`). Within `gdb`, enter `lay next` and hit enter until your terminal window displays both your code and the disassembled assembly corresponding to it (pictured) ![image](https://hackmd.io/_uploads/rkNB9XDo6.png) Let's first run the code as is: enter `run` into `gdb` and notice that it halts execution upon receiving the SIGFPE exception. You should be able to see exactly which instruction caused the exception: ![image](https://hackmd.io/_uploads/SkjA5mvo6.png) The value pointed out is the address of the instruction that caused the error, the `idivl` instruction that tries to divide by 0. Keep this in mind as we move on. The place in the code where we create a pointer to the PC and adjust its value to the next viable instruction in `main` will be in the signal handler function _after_ the `printf` statement, so let's set a breakpoint in the signal handler _after_ the `printf` statement is executed. ![image](https://hackmd.io/_uploads/Hy65sQDsa.png) Then, run `continue`. Execution should halt at the end of the signal handler function. Now is the right time to inspect the values on the stack and see if we can find out where the program counter is relative to the `signalno` parameter. Note in the screenshot above that `signalno=8`. To inspect the values on the stack at any given point in the program's execution, we can print out the first `n` 4-byte values (integers) on the stack with the command `x/nx $sp`, where `$sp` refers to the stack pointer. Note in the following screenshot that we can clearly see an integer whose value is `8`, the same as `signalno`, and an integer whose value is `0x56556212`, the memory address of the faulty `idivl` instruction noted in a previous screenshot. ![image](https://hackmd.io/_uploads/Hyjo67wjp.png) Clearly, the value on the stack corresponding to the memory address of the `idivl` instruction is the program counter, and the value containing the number 8 is `signalno`. We can count the number of integer values between these two values to figure out exactly how much to increment a pointer to `signalno` by to get a pointer to the PC instead. The advantage of doing things in terms of 4-byte values is that we can do all our work with `int`, `int*` and simple addition operands, without any casting at all. ### Length of the Offending Instruction In the case of this program, the line `z=x/y;` actually translates to two instructions: one to do the actual division, and one that moves the new computed value to the address of `z` on the stack. Rerun the program in `gdb` by issuing `run` again. Note the two instructions that must be skipped for execution to flow normally: ![image](https://hackmd.io/_uploads/By4oCmvsa.png) The visual tells us that the `idivl` instruction is exactly 74 words (4-byte values i.e. integers) from the beginning of main, the `mov` instruction is 77 words from main, and the `sub` instruction, which we want to skip to, is 80 words from main. Given that our program counter currently points to the address of the `idivl` instruction, and that we want to skip to the `sub` instruction, it stands to reason that we should increment the program counter by the difference between `80` and `74`. You could, of course, also take the difference of their memory addresses; the result is the same. ## Writing the Code We now need only write some code in the signal handler after the `printf` statement that 1. Gets a pointer to `signalno` (using the `&` operator) 2. Increments the pointer by the integer amount corresponding to the number of values between `signalno` and the program counter on the stack 3. Dereferences the newly modified pointer, then increments the value it points to by the integer amount corresponding to the length of the offending instructions (as discussed immediately above). No other modifications should be necessary.