I'm getting intermittent core dumps in one of our processes.
All of the threads' stacks, aside from the one which crashed, seem OK, and parsed correctly.
The thread that crashes has an apparently corrupted call stack.
The stack is has two frames, both of them 0x00000000.
Looking on the registers, both PC and RA are 0 (which explains the call stack...)
The cause register is 00800008.
Is there a way I can get more information on the crashed thread?
How come the registers themselves are corrupted? (Or is it the other way around, in core dump the debugger fills these registers based on the stack?)
Thanks!
To answer (2) first -- because understanding what actually happened is important for finding out more information about the root cause of the crash:
It really is the registers themselves, in the machine at runtime, that are 0; but it's not that the registers themselves got corrupted; rather, memory got corrupted, and that corrupted memory then got copied back into the registers, which finally caused the crash.
What's happening is something like this: the stack becomes corrupted, including (a) specifically the RA, while it is stored on the stack memory, gets zeroed out. Then, when the function is ready to return, it (b) restores the RA register from the stack -- so the RA register is now 0 -- and then (c) jump-returns to the RA, thus setting the PC to also point to 0; the next instruction will then cause a crash, while both the RA and PC are 0.
That business about the RA being stored on the stack and then restored from it is explained, for example, at http://logos.cs.uic.edu/366/notes/mips%20quick%20tutorial.htm (emphasis mine):
return address stored in register $ra; if subroutine will call other subroutines, or is
recursive, return address should be copied from $ra onto stack to preserve it,
since jal always places return address in this register and hence will overwrite
previous value.
Here's an example program which crashes with PC and RA both 0, and which illustrates the above sequence nicely (the exact numbers may have to be tweaked, depending on the system):
#include <string.h>
int bar(void)
{
char buf[10] = "ABCDEFGHI";
memset(buf, 0, 50);
return 0;
}
int foo(void)
{
return bar();
}
int main(int argc, char *argv[])
{
return foo();
}
And if we look at the disassembly of foo():
(gdb) disas foo
Dump of assembler code for function foo:
0x00400408 <+0>: addiu sp,sp,-32
0x0040040c <+4>: sw ra,28(sp)
0x00400410 <+8>: sw s8,24(sp)
0x00400414 <+12>: move s8,sp
0x00400418 <+16>: jal 0x4003a0 <bar>
0x0040041c <+20>: nop
0x00400420 <+24>: move sp,s8
0x00400424 <+28>: lw ra,28(sp)
0x00400428 <+32>: lw s8,24(sp)
0x0040042c <+36>: addiu sp,sp,32
0x00400430 <+40>: jr ra
0x00400434 <+44>: nop
End of assembler dump.
we see very nicely that RA gets stored on the stack at the beginning of the function (<+4> sw ra,28(sp)) and then is restored at the end (<+28> lw ra,28(sp)) and then jump-returned to (<+40> jr ra). I showed foo() because it's shorter, but the exact same structure is true for bar() -- except that in bar() there is also the memset() in the middle, which overwrites RA while it is on the stack (it's writing 50 bytes into an array of size 10); and then what gets restored into the register is 0, ultimately causing the crash.
So, now we understand that the root cause of the crash is some kind of stack corruption, which gets us back to question (1): is there any way way to get more information about the crashed thread?
Well, this is a bit more difficult, and is where debugging becomes more of an art than a science, but here are the principles to keep in mind:
The basic idea is to figure out what is causing the stack corruption -- most likely, it is a write to some local buffer, as in the example above.
Try to zero in as much as possible on where in the flow the corruption is occurring. Logging can help a lot here: the last log you see obviously happened before the crash (though not necessarily before the corruption!) -- add more logging in the suspect area to zero in on the crash location. Of course, if you have access to a debugger, you can also step through the code to figure out where it's crashing.
Once you find the crash location, it's much easier to work backwards from there: first of all, before the crash, the PC is not yet set to 0, and therefore you should be able to see a backtrace (though, note that the backtrace itself is "calculated" using the values stored on the stack -- once they are corrupted, the backtrace can't be calculated beyond the corruption. But this is actually helpful in this case: this can tell you quite precisely where in memory the corruption is: the point at which the backtrace is truncated is the RA (on the stack) which got corrupted.)
Once you have found what is being corrupted, but you still don't know what is causing the corruption, use watchpoints: as soon as you enter the function which places the RA that is ultimately overwritten on the stack, set a watchpoint on it. That should cause a break as soon as the corruption occurs...
Hope this helps!
Related
I have a C++ program that reports a crash. Analyzing it further, I am able to figure out the exact place where the data on stack gets corrupted. But, I am not able to understand why that happens or what would cause such corruption. At a point in time
value at [rsp+40h] is 00000249 15ed4de0
Then the following assembly instruction gets executed
mov rsi,qword ptr [rsp+40h]
Now, the value at
[rsp+40h] is 00000000 15ed4de0
The higher order DWORD has changed from 00000249 to 00000000. There are no changes in the addresses nearby. I do not understand why a read from [rsp+40h] would end up corrupting the value present at that address.
Any pointers are welcome. Thanks in advance.
I'm learning things about function stack based on assembly using the system Linux x86.
I've read some article, which told me that a function stack (callee) would save the return address where it is called by the caller so that the computer could know the point where to continue when the function returns.
This is why there is a kind of attack: stack smashing.
The stack smashing means that if we can overflow a function stack, especially overflow the return address with a designed address, the program will execute the codes of hackers.
However, today I'm trying to use gdb to check a simple c++ program as below but I can't find any saved return address in any function stack.
Here is the code:
void func(int x)
{
int a = x;
int b = 0; // set a breakpoint
}
int main()
{
func(10); // set a breakpoint
return 0;
}
Then I use gdb to get its assembly:
main:
func:
Now we can see that there is no return address being saved in the two function stacks (at least this is my view).
If a hacker wants to hack this program with stack smashing, which address in the function stack will be edited illegally by him?
Yes there is. Examine the stack immediately before the callq and immediately after it. You will find that the address of the instruction following the callq now appears on the top of the stack and RSP has decremented by 8.
The callq instruction causes the address of the following instruction to be pushed onto the stack. Inversely, the retq instruction at the end of the function causes the address on the stack to be popped into the RIP.
Now we can see that there is no return address being saved in the two function stacks (at least this is my view).
What you are actually showing is the disassembled code, not the stack.
The return address is pushed on the stack by the caller by means of the callq instruction. At the moment of entering the callee function it is at the top of the stack, i.e.: at that moment, rsp contains the address where the return address is stored.
Inspecting the stack with GDB
p/x $rsp displays the value of the rsp register, i.e.: the address of the top of the stack, since rsp points to the top of the stack.
x/x $rsp displays the memory contents located at the top of stack (i.e.: the contents located at the address pointed by rsp).
With this information in mind you can run the command x/x $rsp at the moment of entering the callee function (before anything else is pushed onto the stack) to obtain the return address.
You can also use the command info frame to inspect the current stack frame. The displayed field with the name saved rip corresponds to the current function's return address. However, you need to run this command after the stack frame for the current function has been created and before it is destroyed (i.e.: after mov %rsp,%rbp but before pop %rbp inside the callee).
I know data in nested function calls go to the Stack.The stack itself implements a step-by-step method for storing and retrieving data from the stack as the functions get called or returns.The name of these methods is most known as Prologue and Epilogue.
I tried with no success to search material on this topic. Do you guys know any resource ( site,video, article ) about how function prologue and epilogue works generally in C ? Or if you can explain would be even better.
P.S : I just want some general view, not too detailed.
There are lots of resources out there that explain this:
Function prologue (Wikipedia)
x86 Disassembly/Calling Conventions (WikiBooks)
Considerations for Writing Prolog/Epilog Code (MSDN)
to name a few.
Basically, as you somewhat described, "the stack" serves several purposes in the execution of a program:
Keeping track of where to return to, when calling a function
Storage of local variables in the context of a function call
Passing arguments from calling function to callee.
The prolouge is what happens at the beginning of a function. Its responsibility is to set up the stack frame of the called function. The epilog is the exact opposite: it is what happens last in a function, and its purpose is to restore the stack frame of the calling (parent) function.
In IA-32 (x86) cdecl, the ebp register is used by the language to keep track of the function's stack frame. The esp register is used by the processor to point to the most recent addition (the top value) on the stack. (In optimized code, using ebp as a frame pointer is optional; other ways of unwinding the stack for exceptions are possible, so there's no actual requirement to spend instructions setting it up.)
The call instruction does two things: First it pushes the return address onto the stack, then it jumps to the function being called. Immediately after the call, esp points to the return address on the stack. (So on function entry, things are set up so a ret could execute to pop that return address back into EIP. The prologue points ESP somewhere else, which is part of why we need an epilogue.)
Then the prologue is executed:
push ebp ; Save the stack-frame base pointer (of the calling function).
mov ebp, esp ; Set the stack-frame base pointer to be the current
; location on the stack.
sub esp, N ; Grow the stack by N bytes to reserve space for local variables
At this point, we have:
...
ebp + 4: Return address
ebp + 0: Calling function's old ebp value
ebp - 4: (local variables)
...
The epilog:
mov esp, ebp ; Put the stack pointer back where it was when this function
; was called.
pop ebp ; Restore the calling function's stack frame.
ret ; Return to the calling function.
C Function Call Conventions and the Stack explains well the concept of a call stack
Function prologue briefly explains the assembly code and the hows and whys.
The gen on function perilogues
I am quite late to the party & I am sure that in the last 7 years since the question was asked, you'd have gotten a way clearer understanding of things, that is of course if you chose to pursue the question any further. However, I thought I would still give a shot at especially the why part of the prolog & the epilog.
Also, the accepted answer elegantly & quite simply explains the how of the epilog & the prolog, with good references. I only intend to supplement that answer with the why (at least the logical why) part.
I will quote the below from the accepted answer & try to extend it's explanation.
In IA-32 (x86) cdecl, the ebp register is used by the language to keep
track of the function's stack frame. The esp register is used by the
processor to point to the most recent addition (the top value) on the
stack.
The call instruction does two things: First it pushes the return
address onto the stack, then it jumps to the function being called.
Immediately after the call, esp points to the return address on the
stack.
The last line in the quote above says immediately after the call, esp points to the return address on the stack.
Why's that?
So let's say that our code that's getting currently executed has the following situation, as shown in the (really badly drawn) diagram below
So our next instruction to be executed is, say at the address 2. This is where the EIP is pointing. The current instruction has a function call (that would internally translate to the assembly call instruction).
Now ideally, because the EIP is pointing to the very next instruction, that would indeed be the next instruction to get executed. But since there's sort of a diversion from the current execution flow path, (that is now expected because of the call) the EIP's value would change. Why? Because now another instruction, that may be somewhere else, say at the address 1234 (or whatever), may need to get executed. But in order to complete the execution flow of the program as was intended by the programmer, after the diversion activities are done, the control must return back to the address 2 as that is what should have been executed next should the diversion have not happened. Let us call this address 2 as the return address in the context of the call that is being made.
Problem 1
So, before the diversion actually happens, the return address, 2, would need to be stored somewhere temporarily.
There could have been many choices of storing it in any of the available registers, or some memory location etc. But for (I believe good reason) it was decided that the return address would be stored onto the stack.
So what needs to be done now is increment the ESP (the stack pointer) such that the top of the stack now points at the next address on the stack. So TOS' (TOS before the increment) which was pointing to the address, say 292, now gets incremented & starts pointing to the address 293. That is where we put our return address 2. So something like this:
So it looks like now we have achieved our goal of temporarily storing the return address somewhere. We should now just go about making the diversion call. And we could. But there's a small problem. During the execution of the called function, the stack pointer, along with the other register values, could be manipulated multiple times.
Problem 2
So, although the return address of ours, is still stored on the stack, at location 293, after the called function finishes off executing, how would the execution flow know that it should now goto 293 & that's where it would find the return address?
So (I believe for good reason again) one of the ways of solving the above problem could be to store the stack address 293 (where the return address is) in a (designated) register called EBP. But then what about the contents of EBP? Would that not be overwritten? Sure, that's a valid point. So let's store the current contents of EBP on to the stack & then store this stack address into EBP. Something like this:
The stack pointer is incremented. The current value of EBP (denoted as EBP'), which is say xxx, is stored onto the top of the stack, i.e. at the address 294. Now that we have taken a backup of the current contents of EBP, we can safely put any other value onto the EBP. So we put the current address of the top of the stack, that is the address 294, in EBP.
With the above strategy in place, we solve for the Problem 2 discussed above. How? So now when the execution flow wants to know where from should it fetch the return address, it would :
first get the value from EBP out and point the ESP to that value. In our case, this would make TOS (top of stack) point to the address 294 (since that is what is stored in EBP).
Then it would restore the previous value of EBP. To do this it would simply take the value at 294 (the TOS), which is xxx (which was actually the older value of EBP), & put it back to EBP.
Then it would decrement the stack pointer to go to the next lower address in the stack which is 293 in our case. Thus finally reaching 293 (see that's what our problem 2 was). That's where it would find the return address, which is 2.
It will finally pop this 2 out into the EIP, that's the instruction that should have ideally been executed should the diversion have not happened, remember.
And the steps that we just saw being performed, with all the jugglery, to store the return address temporarily & then retrieve it is exactly what gets done with the function prolog (before the function call) & the epilog (before the function ret). The how was already answered, we just answered the why as well.
Just an end note: For the sake of brevity, I have not taken care of the fact that the stack addresses may grow the other way round.
Every function has an identical prologue(The starting of function code) and epilogue ( The ending of a function).
Prologue: The structure of Prologue is look like:
push ebp
mov esp,ebp
Epilogue: The structure of Prologue is look like:
leave
ret
More in detail : what is Prologue and Epilogue
Often I see ARM stack traces (read: Android NDK stack traces) that terminate with an lr pointer, like so:
#00 pc 001c6c20 /data/data/com.audia.dev.qt/lib/libQtGui.so
#01 lr 80a356cc /data/data/com.audia.dev.rta/lib/librta.so
I know that lr stands for link register on ARM and other architectures, and that it's a quick way to store a return address, but I don't understand why it always seems to store a useless address. In this example, 80a356cc cannot be mapped to any code using addr2line or gdb.
Is there any way to get more information? Why must the trace stop at the lr address anyway?
Stumbled on the answer finally. I just had to be more observant. Look at the following short stack trace and the information that comes after it:
#00 pc 000099d6 /system/lib/libandroid.so
#01 lr 80b6c17c /data/data/com.audia.dev.rta/lib/librta.so
code around pc:
a9d899b4 bf00bd0e 2102b507 aa016d43 28004798
a9d899c4 9801bfa8 bf00bd0e 460eb573 93004615
a9d899d4 6d842105 462b4632 200047a0 bf00bd7c
a9d899e4 b100b510 f7fe3808 2800edf4 f04fbf14
a9d899f4 200030ff bf00bd10 b097b5f0 4614af01
code around lr:
80b6c15c e51b3078 e5933038 e5932024 e51b302c
80b6c16c e1a00002 e3a01000 e3a02000 ebfeee5c
80b6c17c e1a03000 e50b303c e51b303c e1a03fa3
80b6c18c e6ef3073 e3530000 0a000005 e59f34fc
80b6c19c e08f3003 e1a00003 e51b103c ebfeebe6
Now the lr address is still a 80xxxxxx address that isn't useful to us.
The address it prints from the pc is 000099d6, but look at the next section, code around pc. The first column is a list of addresses (you can tell from the fact that it increments by 16 each time.) None of those addresses looks like the pc address, unless you chop off the first 16 bits. Then you'll notice that the a9d899d4 must correspond to 000099d4, and the code where the program stopped is two bytes in from that.
Android's stack trace seems to have "chopped off" the first 2 bytes of the pc address for me, but for whatever reason it does not do it for addresses in the leaf register. Which brings us to the solution:
In short, I was able to chop off the first 16 bits from the 80b6c17c address to make it 0000c17c, and so far that has given me a valid code address every time that I can look up with gdb or addr2line. (edit: I've found it's actually usually the first 12 bits or first 3 hexadecimal digits. You can decide this for yourself by looking at the stack trace output like I described above.) I can confirm that it is the right code address as well. This has definitely made debugging a great bit easier!
Do you have all debugging info (-g3) on?
Gcc likes to use the lr as a normal register. Remember that a non-leaf function looks like
push {lr}
; .. setup args here etc.
bl foo ; call a function foo
; .. work with function results
pop {pc}
Once it pushed lr to the stack, the compiler can use it almost freely - lr will be overwritten only by function calls. So its quite likely that there is any intermediate value in lr.
This should be stated in the debugging information that the compiler generates, in order to let the debugger know it has to look at the stack value instead of lr.
So this code has the off-by-one error:
void foo (const char * str) {
char buffer[64];
strncpy(buffer, str, sizeof(buffer));
buffer[sizeof(buffer)] = '\0';
printf("whoa: %s", buffer);
}
What can malicious attackers do if she figured out how the function foo() works?
Basically, to what kind of security potential problems is this code vulnerable?
I personally thought that the attacker can't really do anything in this case, but I heard that they can do a lot of things even if they are limited to work with 1 byte.
The only off-by-one error I see here is this line:
buffer[sizeof(buffer)] = '\0';
Is that what you're talking about? I'm not an expert on these things, so maybe I've overlooking something, but since the only thing that will ever get written to that wrong byte is a zero, I think the possibilities are quite limited. The attacker can't control what's being written there. Most likely it would just cause a crash, but it could also cause tons of other odd behavior, all of it specific to your application. I don't see any code injection vulnerability here unless this error causes your app to expose another such vulnerability that would be used as the vector for the actual attack.
Again, take with a grain of salt...
Read Shell Coder's Handbook 2nd Edition for lots of information.
Disclaimer: This is inferred knowledge from some research I just did, and should not be taken as gospel.
It's going to overwrite part or all of your saved frame pointer with a null byte - that's the reference point that your calling function will use to offset it's memory accesses. So at that point the calling function's memory operations are going to a different location. I don't know what that location will be, but you don't want to be accessing the wrong memory. I won't say you can do anything, but you might be able to do something.
How do I know this (really, how did I infer this)? Smashing the stack for Fun and Profit by Aleph One. It's quite old, and I don't know if Windows or Compilers have changed the way the stack behaves to avoid these problems. But it's a starting point.
example1.c:
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
void main() {
function(1,2,3);
}
To understand what the program does to call function() we compile it with
gcc using the -S switch to generate assembly code output:
$ gcc -S -o example1.s example1.c
By looking at the assembly language output we see that the call to
function() is translated to:
pushl $3
pushl $2
pushl $1
call function
This pushes the 3 arguments to function backwards into the stack, and
calls function(). The instruction 'call' will push the instruction pointer
(IP) onto the stack. We'll call the saved IP the return address (RET). The
first thing done in function is the procedure prolog:
pushl %ebp
movl %esp,%ebp
subl $20,%esp
This pushes EBP, the frame pointer, onto the stack. It then copies the
current SP onto EBP, making it the new FP pointer. We'll call the saved FP
pointer SFP. It then allocates space for the local variables by subtracting
their size from SP.
We must remember that memory can only be addressed in multiples of the
word size. A word in our case is 4 bytes, or 32 bits. So our 5 byte buffer
is really going to take 8 bytes (2 words) of memory, and our 10 byte buffer
is going to take 12 bytes (3 words) of memory. That is why SP is being
subtracted by 20. With that in mind our stack looks like this when
function() is called (each space represents a byte):
bottom of top of
memory memory
buffer2 buffer1 sfp ret a b c
<------ [ ][ ][ ][ ][ ][ ][ ]
top of bottom of
stack stack
What can malicious attackers do if she
figured out how the function foo()
works? Basically, to what kind of
security potential problems is this
code vulnerable?
This is probably not the best example of a bug that could be easily exploited for security purposes although it could exploited to potentially crash the code simply by using a string of 64-characters or longer.
While it certainly is a bug that will corrupt the address immediately after the array (on the stack) with a single zero byte, there is no easy way for a hacker to inject data into the corrupted area. Calling the printf() function will push parameters on the stack and may clear the zero that was written out of array bounds and lead to a potentially unterminated string being passed to printf.
However, without intimate knowledge of what goes on in printf (and needing to exploit printf as well as foo), a hacker would be hard pressed to do anything other than crash your code.
FWIW, this is a good reason to compile with warnings on or to use functions like strncpy_s which both respects buffer size and also includes a terminating null even if the copied string is larger than the buffer. With strncpy_s, the line "buffer[sizeof(buffer)] = '\0';" is not even necessary.
The issue is that you don't have permission to write to the item after the array. When you asked for 64 chars for buffer, the system is required to give you at least 64 bytes. It's normal for the system to give you more than that -- in which case the memory belongs to you and there is no problem in practice -- but it is possible that even the first byte after the array belongs to "somebody else."
So what happens if you overwrite it? If the "somebody else" is actually inside your program (maybe in a different structure or thread) the operating system probably won't notice you trampled on that data, but that other structure or thread might. There's no telling what data should be there or how trampling over it will affect things.
In this case you allocated buffer on the stack, which means (1) the somebody else is you, and in fact is your current stack frame, and (2) it's not in another thread (but could affect other local variables in the current stack frame).