I am using the Hope functional program on Ubuntu 14.04 with gcc 4.8.2, and doing a highly recursive function to find a large number of prime numbers. However, I get a segmentation fault: 0x000000000040e03f in reach
cell=<error reading variable: Cannot access memory at address 0x7fffff7feff8> at runtime.c:250
The segmentation fault occurs when accessing address 0x7fffff7feff8.
What the reach routine is doing is unmarking heap items that can be reached by the current expression (using a garbage collection mark-sweep). The stack is very deep (100000+ calls), but there is not a stack overflow:
base_memory = 0x7ffff35a4010
top_string = 0x7ffff35a5260
BaseHeap = 0x7ffff35a5260
heap = 0x7ffff603a450
stack = 0x7ffff72da498
TopStack = 0x7ffff7584d60
The area from base_memory to TopStack was allocated with malloc.
Whenever I get a segment violation, the address is always 0x7fffff7feff8, even with very different functions.
If you google 0x7fffff7feff8 there are quite a few entries with segment violations with this address, with no solution to the problem.
I put code into check that the heap address was in the heap range, but it never failed.
I did a gdb
find 0x7ffff35a4010,0x7ffff7584d60,0x7fffff7feff8
and nothing was found.
Why does the address 0x7fffff7feff8 show up in so many problems? Is there something amiss with the stack mechanism, or do I need to change the code in some way for the platform?
This rather looks like a stack overflow on an x86-64 system without adress space layout randomization. If the stack begins at 0x7ffffffff000, as they do on such systems, 0x7fffff7feff8 is suspiciously close to 8 MB below the beginning of the stack, which is a common default thread stack size on Linux systems.
Dump the contents of /proc/self/maps and check if the start of the stack matches this (it is listed at the bottom), and check ulimit -s to see the stack size new processes get. If /proc/self/maps lists 0x7ffffffff000 as end of the stack address range andulimit -s prints 8192, what you have is simply a stack overflow. In this event, a quick fix would be to increase the stack size of new processes (subprocesses of the active shell) like so:
ulimit -Ss size_in_kilobytes
This will work up to a hard limit root may or may not impose. In the long run, it would probably be a good idea to rewrite the code in a less excessively recursive manner.
Also, if all this hits home, you should probably enable ASLR (sysctl kernel.randomize_va_sapce=1. If that complains, your system is in dire need of an upgrade. Write kernel.randomize_va_space = 1 to /etc/sysctl.conf to make it permanent).
Related
I'm reading a book that shows how buffer overflow attacks and one technique to stop it is called Stack Randomization, below is quoted from the book:
a persistent attacker can overcome randomization by brute force, repeatedly attempting attacks with different addresses. A common trick is to include a long sequence of nop (pronounced “no op,” short for “no operation”) instructions before the actual exploit code. Executing this instruction has no effect, other than incrementing the program counter to the next instruction. As long as the attacker can guess an address somewhere within this sequence, the program will run through the sequence and then hit the exploit code. If we set up a 256-byte(28) nop sled, then the randomization over n = 223 can be cracked by enumerating 215 = 32,768 starting addresses
I understand the first part, but don't get the second part about enumerating starting addresses. For example, %rsp points to the current start address as picture below shows (only show 8 bytes instead of 256 bytes for simplicity)
I think what the author mean is, try and guess different address to the stack memory where the %rsp is pointing to. And the padding between return address and %rsp are all nop, and then overwrite the return address with the guessed address which is highly likely points to part of padding(nop). But since Stack Randomization allocats a random amount of space between 0 and n bytes on the stack at the start of a program, so we can only say the probability of successful attack is 215/223 = 0.78%, how can we say try 32,768(a fixed number) addresses then it will be cracked? it is the same as toss a coin, you can only say the probablity of getiing a head is 0.5, you cannot say you will get a head in the second round, becuase you might get two tails
Stack Randomization allocats a random amount of space between 0 and n bytes on the stack at the start of a program
No, it doesn't allocate. It randomizes where in virtual address space the stack is mapped, leaving other pages unmapped. This is with page granularity.
Guessing wrong will typically result in the victim program segfaulting (or whatever the OS does on an invalid page fault). This is noisy and obvious to any intrusion-detection. And if the program does eventually restart so you can try again, its stack address will be re-randomized, as you suggest.
Wrong guesses that land in valid memory but not your NOP sled will also typically crash soon, on an invalid instruction or something that decodes to an invalid memory access.
So yes, you're right, you can't just enumerate the address space, it's only a probabilistic thing. Trying enough times will mean it's likely you succeed, not guaranteed. And trying to enumerate the possible ASLR entropy isn't particularly useful, or any more likely to succeed sooner than guessing the same page every time I think.
But trying different offsets within a single page is useful because OS-driven stack ASLR only has page granularity.
There is some amount of stack space used by env vars and command line args which will vary from system to system, but tend to be constant across invocations of the same program, I think. Unless the vulnerable function is reached from different call chains, or there's a variable-sized stack allocation in a parent function, in which case the buffer's offset within page could vary every run.
Although of course most processes these days run with non-executable stacks, making direct code-injection impossible for stack buffers. A ROP attack (injecting a return address to an existing sequence of bytes that decode to something interesting) is possible if there are any known static data or code addresses. If not, you have to deal with ASLR of code/data, but you don't get to inject NOP sleds.
I tried to help an OP on this question.
I found out that a code like the one below causes segmentation fault randomly even if the stack is set to 2000 Kbytes.
int main ()
{
int a[510000];
a[509999] = 1;
printf("%d", a[509999]);
return 0;
}
As you can see the array is 510000 x 4 bytes = 2040000 bytes.
The stack is set to 2000 Kbytes (2048000 bytes) using ulimit command:
ulimit -s 2000
ulimit -Ss 2000
Based on those numbers the application has room to store the array, but randomly it return segmentation fault.
Any ideas?
There's a few reasons why you can't do this. There are things that are already using parts of your stack.
main is not the first thing on your stack. There are functions called by the real entry point, dynamic linker, etc. that are before main and they are all probably using some of the stack.
Additionally, there can be things that are usually put on the top of the stack to set up execution. Many systems I know put all the strings in argv and all environment variables on top of the stack (which is why main is not the entry point, there's usually code that runs before main that sets up environment variables and argv for main).
And to top it off a part of the stack can be deliberately wasted to increase the randomness of ASLR if your system does that.
Run you program in the debugger, add a breakpoint at main, look up the value of the stack register and examine the memory above it (remember that most likely your stack grows down unless you're on a weird architecture). I bet you'll find lots of pointers and strings there. I just did this on a linux system and as I suspected all my environment variables were there.
The purpose of resource limits (ulimit) on Unix has never really been to micromanage things down to a byte/microsecond, they are there just to stop your program from going completely crazy and taking down the whole system with it. See them not as red lights and stop signs on a proper road, see them as run-off areas and crash barriers on a racetrack.
If you still wants to access the int location in the array, try to compile the code with out the main..this will not invoke _start
check this discussion enter link description here
This simple C program rarely terminates at the same call depth:
#include <stdio.h>
#include <stdlib.h>
void recursive(unsigned int rec);
int main(void)
{
recursive(1);
return 0;
}
void recursive(unsigned int rec) {
printf("%u\n", rec);
recursive(rec + 1);
}
What could be the reasons behind this chaotic behavior?
I am using fedora (16GiB ram, stack size of 8192), and compiled using cc without any options.
EDIT
I am aware that this program will throw a stackoverflow
I know that enabling some compiler optimizations will change the behavior and that the program will reach integer overflow.
I am aware that this is undefined behavior, the purpose of this question is to understand/get an overview of the implementation specific internal behaviors that might explain what we observe there.
The question is more, given that on Linux the thread stack size is fixed and given by ulimit -s, what would influence the available stack size so that the stackoverflow does not always occur at the same call depth?
EDIT 2
#BlueMoon always sees the same output on his CentOS, while on my Fedora, with a stack of 8M, I see different outputs (last printed integer 261892 or 261845, or 261826, or ...)
Change the printf call to:
printf("%u %p\n", rec, &rec);
This forces gcc to put rec on the stack and gives you its address which is a good indication of what's going on with the stack pointer.
Run your program a few times and note what's going on with the address that's being printed at the end. A few runs on my machine shows this:
261958 0x7fff82d2878c
261778 0x7fffc85f379c
261816 0x7fff4139c78c
261926 0x7fff192bb79c
First thing to note is that the stack address always ends in 78c or 79c. Why is that? We should crash when crossing a page boundary, pages are 0x1000 bytes long and each function eats 0x20 bytes of stack so the address should end with 00X or 01X. But looking at this closer, we crash in libc. So the stack overflow happens somewhere inside libc, from this we can conclude that calling printf and everything else it calls needs at least 0x78c = 1932 (possibly plus X*4096) bytes of stack to work.
The second question is why does it take a different number of iterations to reach the end of the stack? A hint is in the fact that the addresses we get are different on every run of the program.
1 0x7fff8c4c13ac
1 0x7fff0a88f33c
1 0x7fff8d02fc2c
1 0x7fffbc74fd9c
The position of the stack in memory is randomized. This is done to prevent a whole family of buffer overflow exploits. But since memory allocations, especially at this level, can only be done in multiple of pages (4096 bytes) all initial stack pointers would be aligned at 0x1000. This would reduce the number of random bits in the randomized stack address, so additional randomness is added by just wasting a random amount of bytes at the top of the stack.
The operating system can only account the amount of memory you use, including the limit on the stack, in whole pages. So even though the stack starts at a random address, the last accessible address on the stack will always be an address ending in 0xfff.
The short answer is: to increase the amount of randomness in the randomized memory layout a bunch of bytes on the top of the stack are deliberately wasted, but the end of the stack has to end on a page boundary.
You won't have the same behaviour between executions because it depends on the current memory available. The more memory you have available, the further you'll go in this recursive function.
Your program runs infinitely as there is no base condition in your recursive function. Stack will grow continuously by each function call and will result in stack overflow.
If it would be the case of tail-recursion optimization (with option -O2), then stack overflow will occur for sure. Its invoke undefined behavior.
what would influence the available stack size so that the stackoverflow does not always occur at the same call depth?
When stack overflow occurs it invokes undefined behavior. Nothing can be said about the result in this case.
Your recursive call is not necessarily going to cause undefined behaviour due to stackoverflow (but will due to integer overflow) in practice. An optimizing compiler could simply turn your compiler into an infinite "loop" with a jump instruction:
void recursive(int rec) {
loop:
printf("%i\n", rec);
rec++;
goto loop;
}
Note that this is going to cause undefined behaviour since it's going to overflow rec (signed int overflow is UB). For example, if rec is of an unsigned int, for example, then the code is valid and in theory, should run forever.
The above code can cause two issue:
Stack Overflow.
Integer overflow.
Stack Overflow: When a recursive function is called, all its variable is pushed onto the call stack including its return address. As there is no base condition which will terminate the recursion and the stack memory is limited, the stack will exhausted resulting Stack Overflow exception. The call stack may consist of a limited amount of address space, often determined at the start of the program. The size of the call stack depends on many factors, including the programming language, machine architecture, multi-threading, and amount of available memory. When a program attempts to use more space than is available on the call stack (that is, when it attempts to access memory beyond the call stack's bounds, which is essentially a buffer overflow), the stack is said to overflow, typically resulting in a program crash.
Note that, every time a function exits/return, all of the variables pushed onto the stack by that function, are freed (that is to say, they are deleted). Once a stack variable is freed, that region of memory becomes available for other stack variables. But for recursive function, the return address are still on the stack until the recursion terminates. Moreover, automatic local variables are allocated as a single block and stack pointer advanced far enough to account for the sum of their sizes. You maybe interested at Recursive Stack in C.
Integer overflow: As every recursive call of recursive() increments rec by 1, there is a chance that Integer Overflow can occur. For that, you machine must have a huge stack memory as the range of unsigned integer is: 0 to 4,294,967,295. See reference here.
There is a gap between the stack segment and the heap segment. Now because the size of heap is variable( keeps on changing during execution), therefore the extent to which your stack will grow before stackoverflow occurs is also variable and this is the reason why your program rarely terminates at the same call depth.
When a process loads a program from an executable, typically it allocates areas of memory for the code, the stack, the heap, initialised and uninitialised data.
The stack space allocated is typically not that large, (10s of megabytes probably) and so you would imagine that physical RAM exhaustion would not be an issue on a modern system and the stack overflow would always happen at the same depth of recursion.
However, for security reasons, the stack isn't always in the same place. Address Space Layout Randomisation ensures that the base of the stack's location varies between invocations of the program. This means that the program may be able to do more (or fewer) recursions before the top of the stack hits something inaccessible like the program code.
That's my guess as to what is happening, anyway.
I am programming some embedded device which has 64 MB SDRAM. (C is used as programming language).
Is it possible to make a guess (maybe even a rough guess) about the possible size of the stack of this device?
Referring to memory which gets used when we make allocations such as, e.g.,
char s[100];
int t[50];
etc.
e.g., will it be more than 50KB? etc. that is what I mean with rough
plus when I have variables inside some function f
f()
{
int p;
}
when f() exists, this variable dies right?
So when I call f2():
void f2()
{
char t[100];
}
Only the size of a 100 element char array will be added to the stack size right??
size of int p from previous function is not considered anymore.
All sorts of guesses can be made :) Most (all?) embedded development environments provide mechanisms for allocating device memories (read-only, stack, heap, etc.) This is commonly done through linker directive files or C #pragmas placed in a setup source file. Without more information on your development environment, no accurate guess can be made.
In function f(), variable p will exist on the stack. When the function exits, that location on the stack will likely be used for something else.
As for function f2(), you can expect that 100 bytes from the stack will be assigned to t while this function is executing. The size of p will not be considered.
Note that the stack can be used for other information, so you cannot reliably estimate stack usage without considering other factors. For example, do you expect recursion? The stack can be used to store function call/return information - thereby reducing the amount of space you have for local (stack) variables.
Lastly, I've worked with devices operating with less than 1KB of stack, so assumptions should be made carefully.
your question looks like ,"Guessing the stack size"
Why guess when you can know it exactly its not from the sky ! :)
For an embedded programmer the stack size is always his in hands,one has to handle it through the linker command file that he submit to a loader
some thing like this as below
Linker.cmd
MEMORY
{
.
.
SARAM2 (RWIX) : origin = 0x039000, length = 0x010000 /*64KB*/
.
.
}
SECTIONS
{
.
.
.stack > SARAM2
.sysstack > SARAM2
.
.
}
so its clear that you can set your own stack size provided "the stack size is limited to stack pointer bound"
so it is completely depends on your stack pointer range, if your stack pointer is 16bit you stack size is limited to 2^16 which is 64KB
for instance moving away from firmware programming, in a standard linux machine also
if you go for typing
ulimit -a
you will get your limited stack size,and its extendable up to the boundary where Stack Pointer can point to
BTW These may further help you
Direction of Stack Growth
When Does Stack Really Over Flow
and i also suggest its not a bad idea to monitor your stack size , in other words trying to find Stack pointer value which can make you clear 'what is your stack status ?', especially for an embedded programmer a stack overflow cause severe damage :)
There is a script in the Linux kernel sources that can help you find the functions that heavily allocate on the stack. The script is named checkstack.pl and is located in the scripts directory.
Here is a sample invocation:
$ objdump -d $BUILDDIR/target-isns | perl checkstack.pl x86_64
0x00403799 configfs_handle_events []: 4384
0x004041d6 isns_attr_query []: 4176
0x00404646 isns_target_register []: 4176
The script displays the functions that consumes the most space on the stack. The script can help you make a guess for the stack size required. Also, it helps you determine which functions should be optimized with regard to their stack usage.
You may find that your linker is capable of performing stack requirement analysis - normally by command line option to specify map file content. If you could add information about your toolchain, you will get better advice.
What such analysis gives you is the worst case stack usage and the call path involved for any particular function - for the process total you need to look at the stack usage for main() and any other thread entry points (each of which will have a separate stack). You may need also to consider ISRs which on some targets may use the interrupted process or thread stack, on others there may be a separate interrupt stack.
What linker stack analysis cannot determine is stack usage in the case of recursion or call through function pointers, both of which depend on the prevailing runtime conditions that cannot be determined statically.
For example when we call say, a recursive function, the successive calls are stored in the stack. However, due to an error if it goes on infinitely the error is 'Segmentation fault' (as seen on GCC).
Shouldn't it have been 'stack-overflow'? What then is the basic difference between the two?
Btw, an explanation would be more helpful than wikipedia links (gone through that, but no answer to specific query).
Stack overflow is [a] cause, segmentation fault is the result.
At least on x86 and ARM, the "stack" is a piece of memory reserved for placing local variables and return addresses of function calls. When the stack is exhausted, the memory outside of the reserved area will be accessed. But the app did not ask the kernel for this memory, thus a SegFault will be generated for memory protection.
Modern processors use memory managers to protect processes from each other. The x86 memory manager has many legacy features, one of which is segmentation. Segmentation is meant to keep programs from manipulating memory in certain ways. For instance, one segment might be marked read-only and the code would be put there, while another segment is read/write and that's where your data goes.
During a stack overflow, you exhaust all of the space allocated to one of your segments, and then your program starts writing into segments that the memory manager does not permit, and then you get a segmentation fault.
A stack overflow can manifest as either an explicit stack overflow exception (depending on the compiler and architecture) or as a segmentation fault, i.e., invalid memory access. Ultimately, a stack overflow is the result of running out of stack space, and one possible result of running out of stack space is reading or writing to memory that you shouldn't access. Hence, on many architectures, the result of a stack overflow is a memory access error.
The call stack is being overflowed, however the result of the overflowing is that eventually call-related values are pushed into memory that is not part of the stack and then - SIGSEGV!