Most C programmers are familiar with buffer overflows, and know how to avoid them: delegate. In krb5, for instance, our coding practices recommend using asprintf() for simple string concatenation, and the k5buf module for more complicated constructions. If you delegate your string construction this way, you know you can’t overflow an output buffer unless you screw up really badly.
Integer overflows are comparatively shrouded in mystery. Programmers may be vaguely aware that adding large numbers will produce something other than the sum of the operands, but don’t really know what to watch out for or how to avoid attacks. You can’t delegate your integer operations without rendering your code unreadable (and slow). The web is surprisingly unhelpful. So, here’s what I’ve learned about reducing the risk of integer overflow attacks:
- Every time you write code which parses a number out of a string, or otherwise gets it from another trust domain, imagine that you’re getting the largest number possible.
- Subtract, don’t add. If you find yourself writing “if (current + len > available)”, instead write “if (len > available - current)”. If your code doesn’t allow current to grow larger than available, the subtraction will always yield a positive value and you can’t have overflow problems. (However, you do still have to protect against the possibility of len being negative, if it’s a signed type and you constructed it naively.)
- Use unsigned types for lengths when appropriate. (But avoid comparing signed and unsigned types; the semantics of such comparisons are more complicated than you’d expect.)
- If you do find yourself having to add unbounded values, you can generally test for overflow by checking if (a + b < a), assuming a and b are of the same unsigned type. If you’re adding three values in one operation, or multiplying values, that technique doesn’t work.