Flylib.com

Books Software

 
 
 

Testing Techniques to Find the Sin

Testing Techniques to Find the Sin

If the input is character strings, try feeding the application sizes that tend to cause errors. For example, strings that are 64K or 64K1 bytes long can often cause problems. Other common problem lengths are 127, 128, and 255, as well as just on either side of 32K. Any time that adding one to a number results in either changing sign or flipping back to zero, you have a good test case.

In the cases where youre allowed to feed the programmer numbers directlyone example would be a structured documenttry making the numbers arbitrarily large, and especially hit the corner cases.

Example Sins

A search on integer overflow in SecurityFocus vulnerabilities list yields more than 50 hits and the Common Vulnerabilities and Exposures (CVE) database yields 65 entries as of this writing. Heres a few:

Flaw in Windows Script Engine Could Allow Code Execution

From the CVE (CAN-2003-0010) description:

Integer overflow in JsArrayFunctionHeapSort function used by Windows Script Engine for JScript (JScript.dll) on various Windows operating system allows remote attackers to execute arbitrary code via a malicious web page or HTML e-mail that uses a large array index value that enables a heap-based buffer overflow attack.

The interesting thing about this overflow is that it allows for arbitrary code execution by a scripting language that doesnt allow for direct memory access. The Microsoft bulletin can be found at www.microsoft.com/technet/security/bulletin/MS03-008.mspx.

Integer Overflow in the SOAPParameter Object Constructor

Another scripting language attack, CVE entry CAN-2004-0722, is more thoroughly described on the Red Hat Linux web site (www.redhat.com) as:

Zen Parse reported improper input validation to the SOAPParameter object constructor leading to an integer overflow and controllable heap corruption. Malicious JavaScript could be written to utilize this flaw and could allow
arbitrary code execution.

In the same report, the following was also detailed:

During a source code audit, Chris Evans discovered a buffer overflow and integer overflows, which affect the libpng code inside Mozilla. An attacker could create a carefully crafted PNG file in such a way that it would cause Mozilla to crash or execute arbitrary code when the image was viewed .

Heap Overrun in HTR Chunked Encoding Could Enable Web Server Compromise

Shortly after this problem was announced in June, 2002, widespread attacks were seen against affected IIS servers. More details can be found at www.microsoft.com/ technet/security/Bulletin/MS02-028.mspx, but the root cause was because the HTR handler accepted a length of 64K - 1 from the user , added 1after all, we needed room for the null terminatorand then asked the memory allocator for zero bytes. Its not known whether Bill Gates really said 64K ought to be enough for anybody or if thats an Internet legend, but 64K worth of shell code ought to be enough for any hacker to cause mayhem!

Redemption Steps

Redemption from integer overflows can only truly be had by carefully studying and understanding the problem. That said, there are some steps you can take to make the problem easier to avoid. The first is to use unsigned numbers where possible. The C/C++ standard provides the size_t type for (you guessed it) sizes, and a smart programmer will use it. Unsigned integers are much, much easier to verify than signed integers. It makes no sense to use a signed integer to allocate memory!

Avoid clever codemake your checks for integer problems straightforward and easy to understand. Heres an example of a check for addition overflows that was too smart by half:

int a, b, c;

c = a + b;

if(a ^ b ^c < 0)
 return BAD_INPUT;

This test suffers from a lot of problems. Many of us need a few minutes to figure out just what it is trying to do, and then it also has a problem with false positives and false negatives it only works some of the time. Another example of a check that only works some of the time follows :

int a, b, c;

c = a * b;

if(c < 0)
 return BAD_INPUT;

Even allowing for positive inputs to start with, the code only checks for some overflowsconsider (2^30 + 1) * 8; thats 2^33 + 8and once truncated back to 32-bit, it yields 8, which is both incorrect and not negative. A safer way to do the same thing is to store a 32-bit multiplication in a 64-bit number, and then check to see if the high order bits are set, indicating an overflow.

For code like this:

unsigned a,b;
...
if (a * b < MAX) {
 ...
}

you could simply bound the a and b variables to a value you know is less than MAX. For example:

#include "limits.h"

#define MAX_A     10000
#define MAX_B    250

assert(UINT_MAX / MAX_A >= MAX_B); // check that MAX_A and MAX_B are small enough

if (a < MAX_A && b < MAX_B) {
 ...
}

If youd like to thoroughly armor your code against integer overflows, you can try using the SafeInt class, written by David LeBlanc (details are in the Other Resources section). Be warned that unless you catch the exceptions thrown by the class, youve exchanged potential arbitrary code execution for a denial of service. Heres an example of how you can use SafeInt:

size_t CalcAllocSize(int HowMany, int Size, int HeaderLen)
{
 try{
    SafeInt<size_t> tmp(HowMany);
    return tmp * Size + SafeInt<size_t>(HeaderLen);
 }
 catch(SafeIntException)
 {
 return (size_t)~0;
 }
}

Signed integers are used as an input for illustrationthis function should be written exclusively with the size_t type. Lets take a look at what happens under the covers. The first is that the value of HowMany is checked to see if it is negative. Trying to assign a negative value to an unsigned SafeInt throws an exception. Next, operator precedence causes you to multiply a SafeInt by Size, which is an int, and will be checked both for overflow and valid range. The result of SafeInt * int is another SafeInt, so you now perform a checked addition. Note that you need to change the incoming int to a SafeInt, because a negative header length would be valid math but doesnt make sensesizes are best represented as unsigned numbers. Finally, in the return, the SafeInt<size_t> is cast back to a size_t, which is a no-op. Theres a lot of complex checking going on, but your code is simple and easy to read.

If youre programming with C#, compile with /checked, and use unchecked statements to exempt individual lines from checking.