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.



19 Deadly Sins of Software Security. Programming Flaws and How to Fix Them
Writing Secure Code
ISBN: 71626751
EAN: 2147483647
Year: 2003
Pages: 239

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net