Incorrect Bitwise Shift of Integer

Description

Incorrect Bitwise Shift of Integer occurs when an integer value is specified to be shifted by a negative amount or an amount greater than or equal to the number of bits contained in the value. Negative shift amounts are undefined across various programming languages, with compilers typically failing to validate these operations. Over-shifting (shifting beyond the bit width) produces architecture-dependent and compiler-dependent results, often explicitly categorized as undefined behavior.

Risk

Incorrect bitwise shifts have severe implications. Undefined behavior invoked. Program crashes possible. Security checks bypassed. Division by zero from over-shift. Memory corruption. Arbitrary code execution in some contexts. Architecture-dependent results. Unpredictable program state. High likelihood when shift amounts come from untrusted input.

Solution

Implement explicit validation checks during implementation to reject negative or excessive shift values before execution. Ensure shift amounts are always within valid range: 0 to (bit_width - 1). Use unsigned types for shift amounts where possible. Add runtime checks before shift operations with variable amounts.

Common Consequences

ImpactDetails
AvailabilityScope: Availability

Denial of service through crashes, exits, or restarts from undefined behavior.
IntegrityScope: Integrity

Unexpected calculation results leading to security check bypasses.

Example Code

Vulnerable Code

// Vulnerable: C code with unchecked shift operations

#include <stdint.h>
#include <stdio.h>

// VULNERABLE: Shift amount from user input
uint32_t vulnerable_left_shift(uint32_t value, int shift_amount) {
    // VULNERABLE: No validation of shift_amount
    // Negative or >= 32 is undefined behavior
    return value << shift_amount;
}

// VULNERABLE: Right shift with signed value
int32_t vulnerable_right_shift(int32_t value, int shift_amount) {
    // VULNERABLE: Negative shift is undefined
    // Also: right-shifting negative values is implementation-defined
    return value >> shift_amount;
}

// VULNERABLE: Division using shift (CVE-2009-4307 pattern)
int vulnerable_divide_by_power_of_2(int value, int power) {
    // VULNERABLE: If power >= 32, shift is undefined
    // Result could be 0, causing division issues
    int divisor = 1 << power;  // Undefined if power >= 32!

    if (divisor == 0) {
        return -1;  // This check may not work due to UB
    }

    return value / divisor;
}

// VULNERABLE: Filesystem block calculation (CVE-2009-4307 pattern)
uint64_t vulnerable_calculate_blocks(uint64_t size, uint32_t block_bits) {
    // VULNERABLE: block_bits from filesystem metadata
    // Attacker can set block_bits >= 64

    // This shift is undefined behavior
    uint64_t block_size = 1ULL << block_bits;

    // May result in divide by zero or incorrect calculation
    return size / block_size;
}

// VULNERABLE: Kernel shift vulnerability (CVE-2020-8835 pattern)
int vulnerable_kernel_shift(unsigned long value, unsigned int shift) {
    // VULNERABLE: shift value from untrusted source
    // Over-shift leads to memory access issues
    unsigned long mask = (1UL << shift) - 1;
    return value & mask;
}

// VULNERABLE: Negative shift in signed integer
int vulnerable_negative_shift(void) {
    int x = 1;
    int shift = -1;  // VULNERABLE: Negative shift

    // Undefined behavior - could be anything
    return x << shift;
}
// Vulnerable: Java shift operations

public class VulnerableShift {

    // VULNERABLE: Java masks shift amount but may produce unexpected results
    public static int vulnerableShift(int value, int shiftAmount) {
        // Java: shiftAmount is masked to 5 bits for int (0-31)
        // But negative values still produce unexpected results
        return value << shiftAmount;

        // If shiftAmount is 33, Java shifts by 33 & 0x1F = 1
        // This may not be the intended behavior
    }

    // VULNERABLE: Long shift with int overflow potential
    public static long vulnerableLongShift(long value, int shiftAmount) {
        // VULNERABLE: shiftAmount could come from untrusted input
        // May not shift as expected if amount is out of range
        return value << shiftAmount;
    }

    // VULNERABLE: Using shift for bit extraction
    public static int vulnerableExtractBits(int value, int position, int width) {
        // VULNERABLE: position + width could exceed 32
        int mask = (1 << width) - 1;  // May overflow
        return (value >> position) & mask;
    }
}
// Vulnerable: JavaScript shift operations

// VULNERABLE: JavaScript converts to 32-bit for shifts
function vulnerableShift(value, amount) {
    // JavaScript: converts value to 32-bit signed integer
    // Shift amount is masked to 5 bits (0-31)

    // Large values lose precision
    // Amount > 31 produces unexpected masking
    return value << amount;
}

// VULNERABLE: Shift with potentially negative amount
function vulnerableDynamicShift(value, amount) {
    // If amount is negative, JavaScript still performs shift
    // but with masked value (e.g., -1 becomes 31)
    return value << amount;  // Unexpected result!
}

// VULNERABLE: Using shift for power of 2
function vulnerablePowerOf2(exponent) {
    // VULNERABLE: exponent >= 32 produces 0 or unexpected value
    return 1 << exponent;
}

Fixed Code

// Fixed: Safe shift operations in C

#include <stdint.h>
#include <stdbool.h>
#include <limits.h>

// FIXED: Validated left shift
uint32_t safe_left_shift(uint32_t value, int shift_amount) {
    // FIXED: Validate shift amount
    if (shift_amount < 0 || shift_amount >= 32) {
        return 0;  // Safe default
    }

    return value << shift_amount;
}

// FIXED: Safe right shift with proper handling
uint32_t safe_right_shift(uint32_t value, int shift_amount) {
    // FIXED: Use unsigned to avoid implementation-defined behavior
    if (shift_amount < 0 || shift_amount >= 32) {
        return 0;
    }

    return value >> shift_amount;
}

// FIXED: Safe division using shift
int safe_divide_by_power_of_2(int value, unsigned int power) {
    // FIXED: Validate power before shift
    if (power >= sizeof(int) * CHAR_BIT) {
        return 0;  // Would be division by huge number anyway
    }

    int divisor = 1 << power;
    return value / divisor;
}

// FIXED: Safe filesystem block calculation
uint64_t safe_calculate_blocks(uint64_t size, uint32_t block_bits) {
    // FIXED: Validate block_bits
    if (block_bits == 0 || block_bits >= 64) {
        return 0;  // Invalid block size
    }

    // FIXED: Also check for reasonable block size
    if (block_bits > 30) {  // > 1GB block size is suspicious
        return 0;
    }

    uint64_t block_size = 1ULL << block_bits;
    return size / block_size;
}

// FIXED: Generic safe shift function
static inline uint64_t safe_shift_left_64(uint64_t value, unsigned int shift) {
    if (shift >= 64) {
        return 0;
    }
    return value << shift;
}

static inline uint64_t safe_shift_right_64(uint64_t value, unsigned int shift) {
    if (shift >= 64) {
        return 0;
    }
    return value >> shift;
}

// FIXED: Kernel-style safe shift
unsigned long safe_kernel_shift(unsigned long value, unsigned int shift) {
    // FIXED: Validate shift amount
    if (shift >= sizeof(unsigned long) * CHAR_BIT) {
        return 0;
    }

    unsigned long mask = (1UL << shift) - 1;
    return value & mask;
}

// FIXED: Macro for compile-time checked shifts
#define SAFE_SHIFT_LEFT(val, shift, type) \
    (((shift) >= 0 && (shift) < (int)(sizeof(type) * CHAR_BIT)) ? \
     ((type)(val) << (shift)) : (type)0)

#define SAFE_SHIFT_RIGHT(val, shift, type) \
    (((shift) >= 0 && (shift) < (int)(sizeof(type) * CHAR_BIT)) ? \
     ((type)(val) >> (shift)) : (type)0)
// Fixed: Safe Java shift operations

public class SafeShift {

    // FIXED: Validated shift operation
    public static int safeShiftLeft(int value, int shiftAmount) {
        // FIXED: Explicit validation
        if (shiftAmount < 0 || shiftAmount >= 32) {
            return 0;  // Safe default
        }

        return value << shiftAmount;
    }

    // FIXED: Safe long shift
    public static long safeLongShiftLeft(long value, int shiftAmount) {
        // FIXED: Validate for 64-bit
        if (shiftAmount < 0 || shiftAmount >= 64) {
            return 0L;
        }

        return value << shiftAmount;
    }

    // FIXED: Safe bit extraction
    public static int safeExtractBits(int value, int position, int width) {
        // FIXED: Validate parameters
        if (position < 0 || width <= 0 || position >= 32 || width > 32) {
            return 0;
        }

        if (position + width > 32) {
            return 0;  // Would read beyond value
        }

        // FIXED: Safe mask creation
        int mask;
        if (width >= 32) {
            mask = -1;  // All bits set
        } else {
            mask = (1 << width) - 1;
        }

        return (value >>> position) & mask;  // Use unsigned right shift
    }

    // FIXED: Safe power of 2
    public static long safePowerOf2(int exponent) {
        if (exponent < 0 || exponent >= 63) {
            return 0L;  // Would overflow or be invalid
        }

        return 1L << exponent;
    }

    // FIXED: Utility class for safe shifts
    public static class ShiftUtils {
        public static int clampShiftAmount(int amount, int maxBits) {
            if (amount < 0) return 0;
            if (amount >= maxBits) return maxBits - 1;
            return amount;
        }
    }
}
// Fixed: Safe JavaScript shift operations

// FIXED: Validated shift function
function safeShiftLeft(value, amount) {
    // FIXED: Validate amount for 32-bit operations
    if (typeof amount !== 'number' || amount < 0 || amount >= 32) {
        return 0;
    }

    // Convert to 32-bit integer explicitly
    return (value | 0) << amount;
}

// FIXED: Safe unsigned right shift
function safeShiftRightUnsigned(value, amount) {
    if (typeof amount !== 'number' || amount < 0 || amount >= 32) {
        return 0;
    }

    return (value >>> amount);
}

// FIXED: Safe power of 2 using BigInt for large values
function safePowerOf2(exponent) {
    if (typeof exponent !== 'number' || exponent < 0) {
        return 0n;
    }

    if (exponent >= 32) {
        // Use BigInt for large exponents
        return 1n << BigInt(exponent);
    }

    return 1 << exponent;
}

// FIXED: Safe bit manipulation library
const SafeBits = {
    shiftLeft: function(value, amount) {
        if (!Number.isInteger(amount) || amount < 0 || amount >= 32) {
            throw new RangeError('Shift amount must be 0-31');
        }
        return (value | 0) << amount;
    },

    shiftRight: function(value, amount) {
        if (!Number.isInteger(amount) || amount < 0 || amount >= 32) {
            throw new RangeError('Shift amount must be 0-31');
        }
        return (value | 0) >> amount;
    },

    shiftRightUnsigned: function(value, amount) {
        if (!Number.isInteger(amount) || amount < 0 || amount >= 32) {
            throw new RangeError('Shift amount must be 0-31');
        }
        return value >>> amount;
    },

    extractBits: function(value, position, width) {
        if (position < 0 || width <= 0 || position + width > 32) {
            throw new RangeError('Invalid bit extraction parameters');
        }

        const mask = (1 << width) - 1;
        return (value >>> position) & mask;
    }
};

CVE Examples

  • CVE-2009-4307: ext4 filesystem overshift causing divide-by-zero.
  • CVE-2020-8835: Linux kernel overshift enabling unauthorized reads and writes.
  • CVE-2015-1607: Signed left-shift of negative integers causing memory errors in libksba.

  • CWE-682: Incorrect Calculation (parent)
  • CWE-189: Numeric Errors (category)

References

  1. MITRE Corporation. "CWE-1335: Incorrect Bitwise Shift of Integer." https://cwe.mitre.org/data/definitions/1335.html
  2. CERT C. "INT34-C. Do not shift an expression by a negative number of bits or by greater than or equal to the number of bits that exist in the operand"
  3. ISO C Standard. "Undefined Behavior in Shift Operations"