Protect the whole address space using mprotect - c++

For my university project I need to WRITE protect the whole address space of the process. I was reading the /proc/self/maps file and parsing the mapping.
So for each entry of the format 08048000-0804c000 r-xp 00000000 08:03 7971106 /bin/cat, I am reading the first two entry(here 08048000 & 0804c000), converting them to decimal. Lets assume the decimal equivalent is A & B respectively. Then I do mprotect((int*)A, B-A, PROT_READ). But this approach is giving me segmentation fault. I can't find out what I did wrong here. May be I've some knowledge gap here which is causing the problem. Someone can give me some suggestions?

Assuming that your implementation is correct, I'd still expect to see segmentation faults.
After all, you're telling the kernel that you don't want to be allowed to write to any part of your memory. Afterwards, you'll just continue to run your process and the next time you try to write anything at all you'll get a segmentation fault because that's no longer allowed.
That'll most likely be when you return from mprotect() after "protecting" the stack.
Thinking a bit more, it's even possible that you're getting segmentation faults while executing memory (i.e. a shared lib, or your executable code) after you've "protected" it.
In fact, all of the bits of memory where it's safe to apply read-only / do-not-execute flags already have those flags set.
I suspect that's the insight this univerity project was meant to give you.

Related

Why is it that we can write outside of bounds in C?

I recently finished reading about virtual memory and I have a question about how malloc works within the Virtual address space and Physical Memory.
For example (code copied from another SO post)
void main(){
int *p;
p=malloc(sizeof(int));
p[500]=999999;
printf("p[0]=%d\n",p[500]); //works just fine.
}
Why is this allowed to happen? Or like why is that address at p[500] even writable?
Here is my guess.
When malloc is called, perhaps the OS decides to give the process an entire page. I will just assume that each page is worth 4KB of space. Is that entire thing marked as writable? That's why you can go as far as 500*sizeof(int) into the page (assuming 32bit system where int is size of 4 bytes).
I see that when I try to edit at a larger value...
p[500000]=999999; // EXC_BAD_ACCESS according to XCode
Seg fault.
If so, then does that mean that there are pages that are dedicated to your code/instructions/text segments and marked as unwrite-able completely separate from your pages where your stack/variables are in (where things do change) and marked as writable? Of course, the process thinks they're next to each order in the 4gb address space on a 32-bit system.
"Why is this allowed to happen?" (write outside of bounds)
C does not require the additional CPU instructions that would typically be needed to prevent this out-of-range access.
That is the speed of C - it trusts the programmer, giving the coder all the rope needed to perform the task - including enough rope to hang oneself.
Consider the following code for Linux:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int staticvar;
const int constvar = 0;
int main(void)
{
int stackvar;
char buf[200];
int *p;
p = malloc(sizeof(int));
sprintf(buf, "cat /proc/%d/maps", getpid());
system(buf);
printf("&staticvar=%p\n", &staticvar);
printf("&constvar=%p\n", &constvar);
printf("&stackvar=%p\n", &stackvar);
printf("p=%p\n", p);
printf("undefined behaviour: &p[500]=%p\n", &p[500]);
printf("undefined behaviour: &p[50000000]=%p\n", &p[50000000]);
p[500] = 999999; //undefined behaviour
printf("undefined behaviour: p[500]=%d\n", p[500]);
return 0;
}
It prints the memory map of the process and the addresses of some different type of memory.
[osboxes#osboxes ~]$ gcc tmp.c -g -static -Wall -Wextra -m32
[osboxes#osboxes ~]$ ./a.out
08048000-080ef000 r-xp 00000000 fd:00 919429 /home/osboxes/a.out
080ef000-080f2000 rw-p 000a6000 fd:00 919429 /home/osboxes/a.out
080f2000-080f3000 rw-p 00000000 00:00 0
0824d000-0826f000 rw-p 00000000 00:00 0 [heap]
f779c000-f779e000 r--p 00000000 00:00 0 [vvar]
f779e000-f779f000 r-xp 00000000 00:00 0 [vdso]
ffe4a000-ffe6b000 rw-p 00000000 00:00 0 [stack]
&staticvar=0x80f23a0
&constvar=0x80c2fcc
&stackvar=0xffe69b88
p=0x824e2a0
undefined behaviour: &p[500]=0x824ea70
undefined behaviour: &p[50000000]=0x1410a4a0
undefined behaviour: p[500]=999999
Or like why is that address at p[500] even writable?
Heap is from 0824d000-0826f000 and &p[500] is 0x824ea70 by chance, so the memory is writeable and readable, but this memory region may contain real data which will be altered! In the case of the sample program it is most likely that it is unused so the write to this memory is not harmful for the process to work.
&p[50000000] is 0x1410a4a0 by chance, which is not in a page the kernel mapped to the process and therefore is unwriteable and unreadable, hence the seg fault.
If you compile it with -fsanitize=address memory accesses will be checked and many but not all illegal memory accesses will be reported by AddressSanitizer. Slowdown is about two times slower than without AddressSanitizer.
[osboxes#osboxes ~]$ gcc tmp.c -g -Wall -Wextra -m32 -fsanitize=address
[osboxes#osboxes ~]$ ./a.out
[...]
undefined behaviour: &p[500]=0xf5c00fc0
undefined behaviour: &p[50000000]=0x1abc9f0
=================================================================
==2845==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xf5c00fc0 at pc 0x8048972 bp 0xfff44568 sp 0xfff44558
WRITE of size 4 at 0xf5c00fc0 thread T0
#0 0x8048971 in main /home/osboxes/tmp.c:24
#1 0xf70a4e7d in __libc_start_main (/lib/libc.so.6+0x17e7d)
#2 0x80486f0 (/home/osboxes/a.out+0x80486f0)
AddressSanitizer can not describe address in more detail (wild memory access suspected).
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/osboxes/tmp.c:24 main
[...]
==2845==ABORTING
If so, then does that mean that there are pages that are dedicated to your code/instructions/text segments and marked as unwrite-able completely separate from your pages where your stack/variables are in (where things do change) and marked as writable?
Yes, see the output of the process' memory map above. r-xp means readable and executable, rw-p means readable and writeable.
Why is this allowed to happen?
One of the primary design goals of the C (and C++) languages is to be as run-time efficient as possible. The designers of C (or C++) could have decided to include a rule in the language specification that said "writing outside the bounds of an array must cause X to happen" (where X is some well-defined behavior, such as a crash or thrown exception)... but had they done so, every C compiler would have been required to generate bounds-checking code for every array access the C program does. Depending on the target hardware and cleverness of the compiler, enforcing a rule like that could easily make every C (or C++) program 5-10 times slower than it currently can be.
So instead of requiring the compiler to enforce array bounds, they simply indicated that writing outside the bounds of the array is undefined behavior -- which is to say, you shouldn't do it, but if you do do it, then there are no guarantees about what will happen, and anything that happens that you don't like is your problem, not theirs.
Real-world implementations are then free to do whatever they want -- for example, on an OS with memory protection you will likely see page-based behavior like you described, or in an embedded device (or on older OS's like MacOS 9, MS-DOS, or AmigaDOS) the computer may just happily let you write to anywhere in memory, because to do otherwise would make the computer too slow.
As a low-level (by modern standards) language, C (C++) expects the programmer to follow the rules, and will only mechanically enforce those rules if/when it can do so without incurring runtime overhead.
Undefined behavior.
That's what it is. You can try to write out of bounds but it's not guaranteed to work. It might work, it might not. What happens is completely undefined.
Why is this allowed to happen?
Because the C and C++ standards allow it. The languages are designed to be fast. Having to check for out of bounds accesses would require a run-time operation, which would slow the program down.
why is that address at p[500] even writable?
It just happened to be. Undefined behavior.
I see that when I try to edit at a larger value...
See? Again, it just happened to segfault.
When malloc is called, perhaps the OS decides to give the process an entire page.
Maybe, but the C and C++ standards don't require such behavior. They only require that the OS make at least the requested amount of memory available for use by the program. (If there's memory available.)
It's simply that in C the concept of an array is rather basic.
The assignment to p[] is in C the same as:
*(p+500)=999999;
and all the compiler does to implement that is:
fetch p;
calculate offset : multiply '500' by the sizeof(*p) -- e.g. 4 for int;
add p and the offset to get the memory address
write to that address.
In many architectures this is implementable in one or two instructions.
Note that not only does the compiler not know that the value 500 is not within the array, it doesn't actually know the array size to begin with!
In C99 and later, some work has been done to make arrays safer, but fundamentally C is a language designed to be fast to compile and fast to run, not safe.
Put another way. In Pascal, the compiler will prevent you from shooting your foot. In C++ the compiler provides ways to make it more difficult to shoot your foot, while in C the compiler doesn't even know you have a foot.
It's undefined behaviour...
if you try to access outside bounds anything may happen, including SIGEGV or corruption elsewhere in the stack that causes your program to produce wrong results, hang, crash later etc..
the memory may be writable without obvious failure on some given run for some compiler/flags/OS/day-of-the-week etc. because:
malloc() might actually allocate a larger sized allocated block wherein [500] can be written to (but on another run of the program, might not), or
[500] might be after the allocated block, but still memory accessible to the program
it's likely that [500] - being a relatively small increment - would still be in the heap, which might extend beyond further than the addresses that malloc calls have so-far yielded due to some earlier reservation of heap memory (e.g. using sbrk()) in preparation for anticipated use
it's vaguely possible that [500] is "off the end of" the heap, and you end up writing to some other memory area, where e.g. over static data, thread-specific data (including the stack)
Why it this allowed to happen?
There's two aspects to this:
checking indices on every access would bloat (add extra machine code instructions) and slow down execution of the program, and generally the programmer can do some minimal validation of indices (e.g. validating once when a function's entered, then using the index however-many times), or generate the indices in a way that guarantees their validity (e.g. looping from 0 to the array size)
managing the memory extremely precisely, such that out-of-bounds access is reported by some CPU fault, is highly dependent on hardware and in general only possible at page boundaries (e.g. granularity in the 1k to 4k range), as well as taking extra instruction (whether within some enhanced malloc function or in some malloc-wrapping code) and time to orchestrate.
In the language described by the 1974 C Reference Manual, the meaning of int arr[10]; at file scope was "reserve a region of consecutive storage locations large enough to hold 10 values of type int, and bind the name arr to the address at the start of that region. The meaning of expression arr[someInt] would then be "multiply someInt by the size of an int, add that number of bytes to the base address of arr, and access whatever int happens to be stored at the resulting address. If someInt is in the range 0..9, the resulting address will fall within the space that was reserved when arr was declared, but the language was agnostic to whether the value would fall within that range. If on a platform where int was two bytes, a programmer happened to know that the address of some object x was 200 bytes past the starting address of arr, then an access to arr[100] would be an access to x. As to how a programmer would happen to know that x was 200 bytes past the start of arr, or why the programmer would want to use the expression arr[100] rather than x to access x, the design of the language was completely agnostic to such things.
The C Standard allows, but does not require, implementations to behave as described above unconditionally, even in cases where the address would fall outside the bounds of the array object being indexed. Code which relies upon such behavior will often be non-portable, but on some platforms may be able to accomplish some tasks more efficiently than would otherwise be possible.

Simple process loader memory mapping

I'm writing a very simple process loader for Linux. The executables I'm loading are already compiled, and I know where each one expects to be found in memory. The first approach I tried was using mmap() to manually place each code or data section at the correct location, like
mmap(addr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0)
which segfaults unless I remove the MAP_FIXED flag because, it seems, the address of one block conflicts with something already in memory, possibly even the loader itself; the address 0x401000 seems to be the problematic one.
I'm not really even sure where to begin with this one. A friend suggested virtualizing memory access operations; I'm not sure what kind of performance hits I'd take for that, and I have no clue how it's done, but it might be an option. What I'd really love to do is create an "empty" process, which would have, as far as it was concerned, full run of the memory, so nothing would be loaded into the user space until I wanted it to be. The whole concept of an "empty" process might be meaningless, but it's the best way to describe what I want. I'm pretty desperate for some references or examples that might help me.
With your process running (maybe snoozing in "sleep(1000);"), look at its /proc/pid/maps. That will tell you what 0x401000 is used for.
~$ sleep 1h &
[3] 2033
~$ cat /proc/2033/maps
00110000-002af000 r-xp 00000000 08:01 1313056 /lib/i386-linux-gnu/libc-2.15.so
...
Here on my box, /bin/sleep doesn't use that block, and neither does my little one-liner program.
You're probably linking in some library which wants to land there?
So one way would be to allocate the block you need way early (long before main() runs -- look elsewhere for that info).
Another way is to link your code to some address you "know" isn't taken (presumably, you're generating the x86 opcodes yourself, or otherwise "linking", so that shouldn't be a stretch).
Another, better, option is to make your code relocatable. The fact that you don't want to replace the entire process's address space (precisely what exec does) more or less says that your code should be just that.
So find a usable address, load the bits there, and, as needed, perform the relocations (so your on-disk file format, if it's not ELF, will need to include reloc info). That's the high road, and the obvious thing you'll want next from your loader.
Of course, that pretty much means reimplementing dlopen() yourself. I assume you're just trying to learn how it works -- if not, man dlopen. Stephane's Rule Zero: it's already there ;-)
Don't forget to support linking other libraries from your code (without duplication), dlclose(), initializers, the various RTLD_* modes, honor MYCUSTOMLD_LIBRARY_PATH, GCC's __thread specifier, etc. ;-)

Why am I not getting a segmentation fault with this code? (Bus error)

I had a bug in my code that went like this.
char desc[25];
char name[20];
char address[20];
sprintf (desc, "%s %s", name, address);
Ideally this should give a segfault. However, I saw this give a bus error.
Wikipedia says something to the order of 'Bus error is when the program tries to access an unaligned memory location or when you try to access a physical (not virtual) memory location that does not exist or is not allowed. '
The second part of the above statement sounds similar to a seg fault. So my question is, when do you get a SIGBUS and when a SIGSEGV?
EDIT:-
Quite a few people have mentioned the context. I'm not sure what context would be needed but this was a buffer overflow lying inside a static class function that get's called from a number of other class functions. If there's something more specific that I can give which will help, do ask.
Anyways, someone had commented that I should simply write better code. I guess the point of asking this question was "can an application developer infer anything from a SIGBUS versus a SIGSEGV?" (picked from that blog post below)
As you probably realize, the base cause is undefined behavior in your
program. In this case, it leads to an error detected by the hardware,
which is caught by the OS and mapped to a signal. The exact mapping
isn't really specified (and I've seen integral division by zero result
in a SIGFPE), but generally: SIGSEGV occurs when you access out of
bounds, SIGBUS for other accessing errors, and SIGILL for an illegal
instruction. In this case, the most likely explination is that your
bounds error has overwritten the return address on the stack. If the
return address isn't correctly aligned, you'll probably get a SIGBUS,
and if it is, you'll start executing whatever is there, which could
result in a SIGILL. (But the possibility of executing random bytes as
code is what the standards committee had in mind when they defined
“undefined behavior”. Especially on machines with no memory
protection, where you could end up jumping directly into the OS.)
A segmentation fault is never guaranteed when you're doing fishy stuff with memory. It all depends on a lot of factors (how the compiler lays out the program in memory, optimizations etc).
What may be illegal for a C++ program may not be illegal for a program in general. For instance the OS doesn't care if you step outside an array. It doesn't even know what an array is. However it does care if you touch memory that doesn't belong to you.
A segmentation fault occurs if you try to do a data access a virtual address that is not mapped to your process. On most operating systems, memory is mapped in pages of a few kilobytes; this means that you often won't get a fault if you write off the end of an array, since there is other valid data following it in the memory page.
A bus error indicates a more low-level error; a wrongly-aligned access or a missing physical address are two reasons, as you say. However, the first is not happening here, since you're dealing with bytes, which have no alignment restriction; and I think the second can only happen on data accesses when memory is completely exhausted, which probably isn't happening.
However, I think you might also get a bus error if you try to execute code from an invalid virtual address. This could well be what is happening here - by writing off the end of a local array, you will overwrite important parts of the stack frame, such as the function's return address. This will cause the function to return to an invalid address, which (I think) will give a bus error. That's my best guess at what particular flavour of undefined behaviour you are experiencing here.
In general, you can't rely on segmentation faults to catch buffer overruns; the best tool I know of is valgrind, although that will still fail to catch some kinds of overrun. The best way to avoid overruns when working with strings is to use std::string, rather than pretending that you're writing C.
In this particular case, you don't know what kind of garbage you have in the format string. That garbage could potentially result in treating the remaining arguments as those of an "aligned" data type (e.g. int or double). Treating an unaligned area as an aligned argument definitely causes SIGBUS on some systems.
Given that your string is made up of two other strings each being a max of 20 characters long, yet you are putting it into a field that is 25 characters, that is where your first issue lies. You are have a good potential to overstep your bounds.
The variable desc should be at least 41 characters long (20 + 20 + 1 [for the space you insert]).
Use valgrind or gdb to figure out why you are getting a seg fault.
char desc[25];
char name[20];
char address[20];
sprintf (desc, "%s %s", name, address);
Just by looking at this code, I can assume that name and address each can be 20 chars long. If that is so, then does it not imply that desc should be minimum 20+20+1 chars long? (1 char for the space between name and address, as specified in the sprintf).
That can be the one reason of segfault. There could be other reasons as well. For example, what if name is longer than 20 chars?
So better you use std::string:
std::string name;
std::string address;
std::string desc = name + " " + address;
char const *char_desc = desc.str(); //if at all you need this

What does "BUS_ADRALN - Invalid address alignment" error means?

We are on HPUX and my code is in C++.
We are getting
BUS_ADRALN - Invalid address alignment
in our executable on a function call. What does this error means?
Same function is working many times then suddenly its giving core dump.
in GDB when I try to print the object values it says not in context.
Any clue where to check?
You are having a data alignment problem. This is likely caused by trying to read or write through a bad pointer of some kind.
A data alignment problem is when the address a pointer is pointing at isn't 'aligned' properly. For example, some architectures (the old Cray 2 for example) require that any attempt to read anything other than a single character from memory only occur through a pointer in which the last 3 bits of the pointer's value are 0. If any of the last 3 bits are 1, the hardware will generate an alignment fault which will result in the kind of problem you're seeing.
Most architectures are not nearly so strict, and frequently the required alignment depends on the exact type being accessed. For example, a 32 bit integer might require only the last 2 bits of the pointer to be 0, but a 64 bit float might require the last 3 bits to be 0.
Alignment problems are usually caused by the same kinds of problems that would cause a SEGFAULT or segmentation fault. Usually a pointer that isn't initialized. But it could be caused by a bad memory allocator that isn't returning pointers with the proper alignment, or by the result of pointer arithmetic on the pointer when it isn't of the correct type.
The system implementation of malloc and/or operator new are almost certainly correct or your program would be crashing way before it currently does. So I think the bad memory allocator is the least likely tree to go barking up. I would check first for an uninitialized pointer and then bad pointer arithmetic.
As a side note, the x86 and x86_64 architectures don't have any alignment requirements. But, because of how cache lines work, and for various other reasons, it's often a good idea for performance to align your data on a boundary that's as big as the datatype being stored (i.e. a 4 byte boundary for a 32 bit int).
Most processors (not x86 and friends.. the blacksheep of the family lol) require accesses to certain elements to be aligned on multiples of bytes. I.e. if you read an integer from address 0x04 that is okay, but if you try to do the same from 0x03 you will cause an interrupt to be thrown.
This is because it's easier to implement the load/store hardware if it's always on a multiple of the data size with which you're working.
Since HP-UX runs only on RISC processors, which typically have such constraints, you should see here -> http://en.wikipedia.org/wiki/Data_structure_alignment#RISC.
Actually HP-UX has its own great forum on ITRC and some HP staff members are very helpful. I just took a look at the same topic you are asking and here are some results. For example the similar problem was caused actually by a bad input parameter. I strongly advise you first to read answers to similar question and if necessary to post your question there.
By the way it is likely that you will be asked to post results of these gdb commands:
(gdb) bt
(gdb) info reg
(gdb) disas $pc-16*8 $pc+16*4
Most of these issues are caused by multiple upstream dependencies linking to different versions of the same library.
For example, both the gnustl and stlport provide distinct implementations of the C++ standard library. If you compile and link against gnustl, while one of your dependencies was compiled and linked against stlport, then you will each have a different implementation of standard functions and classes. When your program is launched, the dynamic linker will attempt to resolve all of the exported symbols, and will discover known symbols at incorrect offsets, resulting in the BUS_ADRALN signal.

Crash within CString

I am observing a crash within my application and the call stack shows below
mfc42u!CString::AllocBeforeWrite+5
mfc42u!CString::operator=+22
No idea why this occuring. This does not occur frequently also.
Any suggestions would help. I have the crash dump with me but not able to progress any further.
The operation i am performing is something like this
iParseErr += m_RawMessage[wMsgLen-32] != NC_SP;
where m_RawMessage is a 512 length char array.
wMsgLen is unsigned short
and NC_SP is defined as
#define NC_SP 0x20 // Space
EDIT:
Call Stack:
042afe3c 5f8090dd mfc42u!CString::AllocBeforeWrite+0x5 * WARNING: Unable to verify checksum for WP Communications Server.exe
042afe50 0045f0c0 mfc42u!CString::operator=+0x22
042aff10 5f814d6b WP_Communications_Server!CParserN1000::iCheckMessage(void)+0x665 [V:\CSAC\SourceCode\WP Communications Server\HW Parser N1000.cpp # 1279]
042aff80 77c3a3b0 mfc42u!_AfxThreadEntry+0xe6
042affb4 7c80b729 msvcrt!_endthreadex+0xa9
042affec 00000000 kernel32!BaseThreadStart+0x37
Well this is complete call stack and i have posted the code snippet as in my original message
Thanks
I have a suggestion that might be a little frustrating for you:
CString::AllocBeforeWrite does implicate to me, that the system tries to allocate some memory.
Could it be, that some other memory operation (specially freeing or resizing of memory) is corrupted before?
A typical problem with C/C++ memory management is, that an error on freeing (or resizing) memory (for example two times freeing the same junk of memory) will not crash the system immediatly but can cause dumps much later -- specially when new memory is to be allocated.
Your situation looks to me quite like that.
The bad thing is:
It can be very difficult to find the place where the real error occurs -- where the heap is corrupted in the first place.
This also can be the reason, why your problem only occurs once in a while. It could depend on some complicated situation beforehand.
I'm sure you'll have checked the obvious: wMsgLen >= 32