Unsigned to Signed Conversion Error

Description

Unsigned to Signed Conversion Error occurs when a large unsigned integer value is converted to a signed integer type. When the unsigned value exceeds the maximum positive value representable by the signed type, the result is a negative number due to the interpretation of the high-order bit as the sign bit. For example, converting unsigned 0xFFFFFFFF to a signed 32-bit integer produces -1. This is particularly dangerous when the negative result is then used in comparisons, array indexing, or as a size parameter, potentially enabling security bypasses or buffer underflows.

Risk

Unsigned to signed conversion errors are particularly insidious because large unsigned values can silently become negative values that bypass security checks. When a large size value becomes negative after conversion, it may pass checks like "if (size > MAX_SIZE)" while later being re-interpreted as a huge value for memory operations. These vulnerabilities are perfect precursors to buffer underwrite conditions, where negative indices allow attackers to access memory before the intended buffer—an area often containing function pointers, return addresses, or other critical control data not reachable via traditional overflows.

Solution

Avoid mixing signed and unsigned integers in the same calculation or comparison. Use consistent types throughout related operations. When conversion is necessary, validate that the unsigned value is within the range of the target signed type before conversion. Use explicit range checks: for 32-bit, ensure value <= INT_MAX before casting to signed. Enable compiler warnings for implicit conversions (-Wconversion). Apply static analysis to identify dangerous conversion patterns.

Common Consequences

ImpactDetails
IntegrityScope: Security Bypass

Large unsigned values converted to negative signed values may bypass size or range checks.
IntegrityScope: Buffer Underwrite

Negative values used as indices access memory before the intended buffer, corrupting critical data.
Access ControlScope: Code Execution

Buffer underwrites can corrupt return addresses and function pointers for code execution.

Example Code + Solution Code

Vulnerable Code

#include <stdlib.h>
#include <string.h>

// VULNERABLE: Large unsigned becomes negative signed
void process_packet(unsigned int packet_size) {
    int size = packet_size;  // Large values become negative

    // Size check passes for negative values!
    if (size > MAX_BUFFER) {
        return;  // Negative -1 is not > MAX_BUFFER
    }

    char buffer[1024];
    // memcpy interprets negative size as huge unsigned
    memcpy(buffer, data, size);  // Overflow!
}

// VULNERABLE: Buffer underwrite via negative index
void write_at_offset(char *buffer, unsigned int offset) {
    int index = offset;  // 0xFFFFFFFF becomes -1

    // Negative index accesses before buffer
    buffer[index] = 'X';  // Underwrite!
}

// VULNERABLE: Comparison bypass
#define MAX_ITEMS 1000
unsigned int items[MAX_ITEMS];

void add_item(unsigned int index, unsigned int value) {
    int idx = index;

    // Negative idx passes this check!
    if (idx < MAX_ITEMS) {
        items[idx] = value;  // Underwrite if idx negative
    }
}

// VULNERABLE: Iteration with converted counter
void process_items(unsigned int count) {
    int i = count;

    // If count > INT_MAX, i is negative - loop doesn't execute
    // Or worse: wraps incorrectly
    for (int j = 0; j < i; j++) {
        process_item(j);
    }
}

Fixed Code

#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <limits.h>

// SAFE: Validate range before conversion
int process_packet_safe(unsigned int packet_size) {
    // Check that value fits in signed type
    if (packet_size > INT_MAX) {
        return -1;  // Reject too-large values
    }

    int size = (int)packet_size;  // Now safe

    if (size > MAX_BUFFER || size <= 0) {
        return -1;
    }

    char buffer[MAX_BUFFER];
    memcpy(buffer, data, (size_t)size);
    return 0;
}

// SAFE: Use unsigned throughout
void write_at_offset_safe(char *buffer, size_t buffer_size,
                          size_t offset) {
    // Keep as unsigned - no conversion
    if (offset >= buffer_size) {
        return;  // Bounds check
    }

    buffer[offset] = 'X';
}

// SAFE: Proper unsigned comparison
#define MAX_ITEMS 1000
unsigned int items[MAX_ITEMS];

void add_item_safe(size_t index, unsigned int value) {
    // Use unsigned comparison
    if (index >= MAX_ITEMS) {
        return;
    }

    items[index] = value;
}

// SAFE: Use consistent unsigned types
void process_items_safe(size_t count) {
    // Keep as unsigned throughout
    if (count > MAX_REASONABLE_COUNT) {
        return;
    }

    for (size_t i = 0; i < count; i++) {
        process_item(i);
    }
}

// Alternative: Explicit range check before conversion
bool safe_to_signed(unsigned int value, int *result) {
    if (value > (unsigned int)INT_MAX) {
        return false;
    }
    *result = (int)value;
    return true;
}

Exploited in the Wild

SoftMaker Office TextMaker (SoftMaker, 2021)

Multiple vulnerabilities in SoftMaker Office TextMaker involving unsigned to signed conversion errors that could enable code execution through crafted documents.

Hyperledger Besu (Hyperledger, 2022)

Denial of service vulnerability in Hyperledger Besu blockchain client caused by unsigned to signed conversion errors in transaction processing.

Historical BSD/UNIX Vulnerabilities (Various, 1990s-2000s)

Multiple classic UNIX vulnerabilities stemmed from unsigned to signed conversion errors in system calls and library functions, particularly in socket and file handling code.


Tools to test/exploit

  • UBSan — detects implicit conversions that change value.

  • Coverity — static analysis for type conversion issues.

  • Clang Static Analyzer — detects suspicious integer conversions.


CVE Examples


References

  1. MITRE. "CWE-196: Unsigned to Signed Conversion Error." https://cwe.mitre.org/data/definitions/196.html

  2. CERT. "INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data." https://wiki.sei.cmu.edu/confluence/display/c/INT31-C