CWE-190: Integer Overflow or Wraparound
Overview
Integer overflow occurs when arithmetic operations produce results larger than the maximum value the integer type can hold, causing the value to wrap around to negative or small positive values. This leads to buffer overflows, incorrect memory allocations, bypassed security checks, and logic errors.
Risk
High: Integer overflows cause buffer overflows (when used for allocation/indexing), authentication bypass (if used in security checks), infinite loops, incorrect business logic, and memory corruption. Classic vulnerability in length calculations and buffer sizing.
Remediation Steps
Core principle: Validate ranges before arithmetic to prevent integer overflow/wraparound.
Locate the integer overflow vulnerability in your code
- Review the flaw details to identify the specific file, line number, and code pattern
- Identify the arithmetic operation that can overflow (addition, multiplication, subtraction)
- Trace the data flow: where do the operands come from (user input, file, network, calculation)
- Determine the impact: is the result used for allocation, indexing, security checks, or business logic
Use safe integer libraries and operations (Primary Defense)
- Use safe arithmetic libraries:
- C++: Use SafeInt library or compiler builtins (
__builtin_add_overflow,__builtin_mul_overflow) - Rust: Use checked arithmetic (
checked_add,checked_mul,saturating_add) - Java: Use
Math.addExact,Math.multiplyExact,Math.subtractExact - C#: Use checked arithmetic blocks (
checked { }) or SafeInt
- C++: Use SafeInt library or compiler builtins (
- Use unbounded integers for large calculations: BigInteger (Java, C#, Python) for values that may exceed native integer limits
- Enable compiler overflow detection: Use
-ftrapv(GCC) or-fsanitize=signed-integer-overflow(Clang) - Avoid unsafe arithmetic: Never perform arithmetic on user-controlled values without overflow checks
Validate operands before arithmetic operations
- Check operands before operations: Verify operands are within safe range before add/multiply/subtract
- Validate allocation sizes: Reject unreasonably large values (> 100MB, > MAX_SAFE_SIZE)
- Use pre-condition checks: Check
a > SIZE_MAX / bbeforea * bto prevent overflow - Verify results are in expected range: After arithmetic, check result is within acceptable bounds
Apply additional integer safety protections
- Use wider integer types: Use
int64_tinstead ofint32_t, perform arithmetic in larger type then check range - Use unsigned types appropriately: Only use unsigned when values should never be negative, be aware of underflow
- Avoid mixing signed/unsigned: Be careful with type promotion and comparison rules
- Bounds check before indexing: Always verify index < array_size before array access
Monitor and audit integer arithmetic usage
- Enable runtime checks in development (compiler sanitizers, debug builds)
- Test with edge cases (MAX_INT, MAX_INT-1, MIN_INT, 0)
- Review code for arithmetic operations on user input (multiplication, addition in allocation)
- Log arithmetic errors in production for security monitoring
Test the integer overflow fix thoroughly
- Test with boundary values (INT_MAX, UINT_MAX, SIZE_MAX, 0, -1)
- Test with values designed to overflow (INT_MAX + 1, SIZE_MAX / 2 * 3)
- Verify safe arithmetic libraries properly detect and handle overflow
- Test with realistic large inputs (file sizes, array lengths, counts)
- Re-scan with security scanner to confirm the issue is resolved
Common Vulnerable Patterns
Unchecked Multiplication in Allocation
#include <stdlib.h>
#include <limits.h>
// Dangerous: overflow in allocation size
void *allocate_buffer(int count, int size) {
// Attack: count=0x40000000, size=4
// total = 0x100000000 -> wraps to 0
int total = count * size;
return malloc(total); // Allocates 0 bytes!
}
Overflow in Bounds Check
#include <stdlib.h>
#include <string.h>
// Dangerous: overflow in bounds check
int copy_data(char *dest, int dest_size, char *src, int src_size) {
// Attack: dest_size=100, src_size=INT_MAX
if (dest_size + src_size < dest_size) { // Overflow! Check fails
return -1;
}
memcpy(dest, src, src_size); // Buffer overflow
}
Unchecked Addition with User Input
#include <stdlib.h>
// Dangerous: unchecked user input
void process_array(int user_count) {
// Attack: user_count = INT_MAX
int buffer_size = user_count + 1; // Overflows to INT_MIN
char *buffer = malloc(buffer_size); // Huge allocation or negative
}
Secure Patterns
Pre-Multiplication Overflow Check (C)
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <stdbool.h>
// Correct: check for overflow before multiplication
bool safe_multiply(size_t a, size_t b, size_t *result) {
if (a > 0 && b > SIZE_MAX / a) {
return false; // Would overflow
}
*result = a * b;
return true;
}
void *allocate_buffer_safe(size_t count, size_t size) {
size_t total;
if (!safe_multiply(count, size, &total)) {
return NULL; // Overflow detected
}
// Additional sanity check
if (total > 1024 * 1024 * 100) { // 100MB limit
return NULL;
}
return malloc(total);
}
// Correct: proper overflow check
int copy_data_safe(char *dest, size_t dest_size,
char *src, size_t src_size) {
// Check for overflow and bounds
if (src_size > dest_size) {
return -1;
}
memcpy(dest, src, src_size);
return 0;
}
Why this works: Checking if b > SIZE_MAX / a before multiplication detects potential overflow by division, preventing wraparound without risking overflow in the check itself.
Compiler Builtin Overflow Detection (GCC/Clang)
#include <stdlib.h>
#include <stdbool.h>
void *allocate_safe_gcc(int count, int size) {
int total;
// Use GCC builtin overflow detection
if (__builtin_mul_overflow(count, size, &total)) {
return NULL; // Overflow detected
}
if (total < 0 || total > 10000000) {
return NULL; // Sanity check
}
return malloc(total);
}
bool safe_add(int a, int b, int *result) {
return !__builtin_add_overflow(a, b, result);
}
Why this works: Compiler builtins provide hardware-level overflow detection with zero performance overhead, catching overflow before it occurs.
Safe Arithmetic with Math.multiplyExact (Java)
import java.math.BigInteger;
public class SafeArithmetic {
public static int safeMultiply(int a, int b) {
try {
return Math.multiplyExact(a, b);
} catch (ArithmeticException e) {
throw new IllegalArgumentException("Integer overflow");
}
}
public static byte[] allocateBuffer(int count, int itemSize) {
// Validate inputs first
if (count < 0 || count > 1000000) {
throw new IllegalArgumentException("Invalid count");
}
if (itemSize < 0 || itemSize > 1000) {
throw new IllegalArgumentException("Invalid item size");
}
// Use safe multiplication
int total = Math.multiplyExact(count, itemSize);
return new byte[total];
}
// For very large calculations
public static BigInteger safeBigMultiply(long a, long b) {
return BigInteger.valueOf(a).multiply(BigInteger.valueOf(b));
}
}
Why this works: Math.multiplyExact() throws ArithmeticException on overflow instead of silently wrapping, allowing proper error handling.
Arbitrary Precision Integers with Practical Limits (Python)
import sys
def allocate_buffer(count: int, size: int) -> bytearray:
# Python 3 integers are unbounded, but validate anyway
if count < 0 or count > 1_000_000:
raise ValueError('Invalid count')
if size < 0 or size > 10_000:
raise ValueError('Invalid size')
total = count * size # Python handles big integers
# Check practical limits
if total > sys.maxsize or total > 100_000_000:
raise ValueError('Buffer too large')
return bytearray(total)
Why this works: Python3 integers are arbitrary precision, but validating against system/practical limits prevents memory exhaustion attacks.