SecureProgramming.com
Login
Username: 
Password: 
Forgot your password?
Create a new account





Avoiding malloc()/new-related integer overflowsCategory: Input Validation
Language: C, C++, and Objective-C
Posted by John Viega on Sun, Sep 14, 2003 (03:58 AM) GMT

Problem
Integer overflows can lead to allocating too little memory, which can often result in an exploitable buffer overflow.

Solution
Before each memory allocation, be sure to check the size you're allocating, to make sure it really is big enough to do what you need.

Discussion
While the following code might seem natural to many, there's the potential for a very big security problem:
char *double_string(char *str, size_t len) {
char *result = (char *)malloc(len*2+1);
if (!result) abort();
strcpy(result, str);
strcat(result, str);
return result;
}
What happens if an attacker can control the value of len, setting it to 2147483648? Multiplying it by 2 returns 0 as a result, due to an integer overflow (The hex for that value is 0x80000000; the leftmost one gets shifted out of the value). The end result is that we only allocate a single byte of memory. Unless str happens to have a NULL as the first byte, the resulting operations will overflow the buffer.

If the length of str is always tied to the value of len and len is an unsigned type instead of a signed type, then an attack is probably not practical, because it would require the actual length of str to be bigger than any memory value you can allocate (in C and C++ you cannot allocate more than INT_MAX bytes, whether statically or dynamically).

If you're using a signed value, then the overflow may be practical, depending on how the data is copied. If using something that copies a fixed number of bytes, things probably won't work since the attacker will usually need to overwrite so much data that the program will crash during the overwrite, before ever transferring control over to the attackers code.

However, if using a string operation, then the attacker only needs to get a null character at the point where the overwrite to stop.

Some people might think this sort of problem isn't a big deal, because there is a misconception that heap overflows are almost always harmless. That's far from the truth. Almost inevitably, there are function pointers in the heap, such as the global offset table used for imported libraries, or the addresses of class methods and exception handlers in C++. An attacker just needs to lay down code to execute, replace a function pointer with a pointer to the attack code and then wait until the function pointer gets dereferenced (which is often inevitable).

Consider an example where a network protocol represents the data in a packet using a length field, followed by a payload. The application may read and malloc() the number of bytes specified by the length, even validating that the packet payload is the right size. But, if the payload happens to have a NULL in it, and the code uses strncpy() or something like that, then the actual amount of data copied could be reasonably small.

Protecting against this kind of attack is usually as simple as validating that any calculation did not wrap around. For example, we could modify the code at the beginning of this recipe as such:
char *double_string(char *str, size_t len) {
size_t tomalloc = len*2+1;
char *result;

if (tomalloc < len || !(result = (char *)malloc(tomalloc))) abort();
strcpy(result, str);
strcat(result, str);
return result;
}


[Python Powered]