allocating a buffer that is too small to hold the data to be copied into it. • Withdrawing 1 dollar from an account with a balance of 0 could cause an integer underflow and yield a new balance of 4,294,967,295. • During online purchase, an integer overflow could allow the total to shift from a positive value to a negative one. This allows give money to the customer in addition to their purchases, when the transaction is completed. Integer Overflow: Security Impact 4
to full read/write in kernel space Integer issue leads to Unexpected Value (UV) or Unexpected Behaviour (UB). An UV is a value other than the one you would expect from your software. In C/C++ by standard, unsigned computations are performed modulo 2, while signed overflow is a classic example of undefined behavior. С++ Secure Coding: Integer security 5
0; //invalid result z = x + y; assert(z == x + y) //assert fails to detect it //since C++ implicitly converts variables //to int before evaluation the expression Integer security: Example 7
and most of C++ programs are don’t have integer range-cheking applied and program get unexpected behavior. Similar issues also actual for floating-point types. Unexpected values are a common source of software vulnerabilities. Also some integer operations are C/C++ valid but not expected by user, for example, when unsigned integer used as array index and “wrap around” С++ Secure Coding 13
• Unsigned: 2n-1, where n is the number of bits used to represent the unsigned type. Standard integers include the following types, in non-decreasing length order: • signed char • short int • int • long int • long long int Signed and Unsigned Types 14
of a cast or implicitly as required by an operation. Conversions can lead to lost or misinterpreted data. Implicit conversions are a consequence of the C/C++ ability to perform operations on mixed types. The following rules influence how conversions are performed: • integer promotions • integer conversion rank Integer Conversions 19
and c2) to int size. Value of the smaller type is converted to int (if possible) or to unsigned int. char cresult, c1, c2, c3; c1 = 100; c2 = 90; c3 = -120; cresult = c1 + c2 + c3; Integer Promotion 20
types to larger unsigned integer types is always safe • Conversions of a larger unsigned integer to a smaller unsigned integer type, the larger value is truncated and low-order bits are preserved When unsigned integer types are converted to the corresponding signed integer type then bit pattern is preserved so no data is lost and high-order bit becomes the sign bit Unsigned Integer conversion 21
unsigned integer type • bit pattern is preserved—no lost data • high-order bit loses its function as a sign bit If the value of the signed integer is not negative, the value is unchanged. If the value is negative, the resulting unsigned value is evaluated as a large, unsigned integer. The only integer type conversion guaranteed safe for all data values and all conforming implementations is to a wider type of the same signed-ness Signed Integer conversion 22
i; //Implicit conversion to smaller //unsigned integer std::cout<< "u=" << u; //There are sufficient bits to //represent the value so //no truncation occurs. The two’s //complement representation //is interpreted as a large signed //value, however, so u = 65533 Sign Error Example 23
beyond its maximum value or decreased beyond its minimum value. Overflows can be signed or unsigned. A signed overflow occurs when a value is carried over to the sign bit. An unsigned overflow occurs when the underlying representation can no longer represent a value. Integer overflow 24
• Integer addition can result in an overflow if the sum cannot be represented in the allocated bits. • Multiplication is prone to overflow errors because relatively small operands can overflow. One solution is to allocate storage for the product that is twice the size of the larger of the two operands. The IA-32 instruction set includes a mul (unsigned multiply) instruction imul (signed multiply) instruction Integer Operations 30
least 2x bits and then multiply. To be compliant with the standard, multiplying two 32-bit numbers in this context must yield a 32-bit result. The language was not modified because the result would be burdensome on architectures that do not have widening multiply instructions. Integer Operations 32
an error if (cBlocks == 0) return NULL; // Allocate enough memory // Upcast the result to a 64-bit integer // and check against 32-bit UINT_MAX // to make sure there's no overflow unsigned long long alloc = cBlocks * 16; return (alloc < UINT_MAX) ? malloc(cBlocks * 16) : NULL; } Upcast Example 33
an error if (cBlocks == 0) return NULL; // Allocate enough memory // Upcast the result to a 64-bit integer // and check against 32-bit UINT_MAX // to make sure there's no overflow unsigned long long alloc = (unsigned long long) cBlocks * 16; return (alloc < UINT_MAX) ? malloc(cBlocks * 16) : NULL; } Upcast Example 34
value for 32-bit or 64-bit integers are divided by -1. In the 32-bit case, –2,147,483,648/-1 should be equal to 2,147,483,648 - 2,147,483,648 /-1 = - 2,147,483,648 Because 2,147,483,648 cannot be represented as a signed 32-bit integer the resulting value is incorrect Integer Division 35
determine whether there are identifiable upper and lower bounds. • These limits should be enforced by the interface. • It’s easier to find and correct input problems than it is to trace internal errors back to faulty inputs. Limit input of excessively large or small integers. Use different compilers with all warnings are no because different compilers have different warnings and error-detection methods Mitigations 37
to provide better types. Using an unsigned type can guarantee that a variable does not contain a negative value. Representing Object Size: Really bad: short total = strlen(argv[1])+ 1; Better: size_t total = strlen(argv[1])+ 1; Better still: rsize_t total = strlen(argv[1])+ 1; Mitigations 40
are frequently a sign that an object’s size was calculated incorrectly. New type, rsize_t, defined to be size_t but explicitly used to hold the size of a single object These features were introduced in C 11 standard, Annex K. rsize_t 41
C _s functions like strncpy_s do nothing and report error when a value of type rsize_t exceeds RSIZE_MAX. rsize_t is the same type as size_t so they are binary compatible rsize_t 42
a hardware exception • a fault such as – an access violation – divide by zero Visual Studio provides structured exception handling (SEH) facility for dealing with hardware and other exceptions Structured exception handling is an operating system facility that is distinct from C++ exception handling. Microsoft Visual Studio 43
{ 3 return ui / divisor; 4 } 5 catch (...) { 6 throw SintException( 7 //C++ exceptions in Visual C++ are implemented using structured 8 //exceptions, making it possible to use C++ exception 9 //handling on this platform. 10 ARITHMETIC_OVERFLOW 11 ); 12 } 13} Microsoft Visual Studio 44
value is assigned to a smaller integer type. At level 3 a warning is issued if __int64 is assigned to unsigned int. At level 4, a “possible loss of data” warning is issued if an integer is converted to a smaller type. 1 int b = 0; //version 19.00.23506 for x64 3 short a = b; // C4244 W4 4 __int64 c = 0; 5 unsigned int d = c; //C4244 W3 Visual C++ Warnings 45
value is assigned to a smaller data type and results in a data loss. To workaround this option with bits manipulations, mask off the information you need to avoid a run-time error int val = 1234567, pos = 2; char res = (char)((val >> pos) & 0xff); Visual C++ Warnings 46
for signed arithmetic overflow on addition, subtraction, and multiplication operations. • Where an overflow is detected, an undefined instruction is inserted into the assembly code. In order for the overflow to get caught, an undefined instruction handler must be provided. • GCC has a bug related to ftrapv since 2008. -fwrapv option: instructs the compiler to assume that signed arithmetic overflow of addition, subtraction and multiplication wraps around using twos-complement representation i.e. removes the UB in this case When both -fwrapv and -ftrapv are used in a single command, the furthest-right option overrides the other. GCC Runtime Checks 47
pointer arithmetic overflow on addition and subtraction wraps around using twos-complement representation. This flag disables some optimizations which assume pointer overflow is invalid. -Wconversion: Warn for implicit conversions that may change a value -Wcast-align: Warn for a pointer cast to a type which has a different size, causing an invalid alignment and subsequent bus error on ARM processors -Wsign-promo: Warn when overload resolution chooses a promotion from unsigned or enumerated type to a signed type, over a conversion to an unsigned type of the same size -fsanitize: address, thread, memory, undefined, etc. GCC Runtime Checks 48
> MAX_INT Error! • A > MAX_INT – B But MAX_INT – B == ~B. This is true if and only if B is unsigned and is 32 bits and or larger. It turns out that the one’s complement (~) operator converts any integer that isn’t 32 bits to a 32-bit signed integer. if(A > ~B) return error; Testing a signed addition operation is considerably more difficult. We actually have four cases—both numbers are positive, both numbers are negative, and two mixed-sign cases. Use correct checking for unsigned integers 50
to work with signed integers: Noncompliant Code Example 1 void func(signed int si_a, signed int si_b) { 2 signed int sum = si_a + si_b; 3 } Use correct checking for signed integers 51
//test for +/- combo. For a signed integer, the uppermost bit declares 3 //the sign. If both inputs are positive, 0^0 = 0, and likewise if both 4 //inputs are negative, 1^1 = 0. either two negatives, or 2 positives 5 if (rhs < 0) { 6 //two negatives 7 if (lhs < MinInt() - rhs) {//remember rhs < 0 8 throw ERROR_ARITHMETIC_OVERFLOW; 9 } 10 //Ok 11 } Use correct checking for signed integers 53
operations. class checks whether an arithmetic overflow occurs or whether the code tries to divide by zero. In both cases, the class calls the error handler to warn the program of the potential problem. template<typename T, typename E = _SAFEINT_DEFAULT_ERROR_POLICY> class SafeInt; E is the error handling mechanism that SafeInt uses • SafeIntErrorPolicy_SafeIntException is the default which throws a SafeIntException Class exception • SafeIntErrorPolicy_InvalidParameter, which stops the program if an error occurs SafeInt Class 55
assembly language instructions • Usability – operators can be used in inline expressions – uses C++ exception handling SafeInt issues: • Incorrect behavior - fails to provide correct integer promotion behavior. • Performance SafeInt Class 57
using two different SafeInt types. SafeInt<T, E> & int is supported, but SafeInt<T, E> & SafeInt<U, E>. • To workaround it, use SafeInt<T, E> & (U)SafeInt<U, E> • For the shift operators, shifting more bits than exist for the template type will throw an ASSERT exception. SafeInt Class 58
((uint)~0) > -1 is false. That’s because SafeInt class realizes that the second parameter is negative whereas the first parameter is unsigned. • In case of ternary operator ?: this will be an issue: int x = flag ? SafeInt<unsigned int>(y) : -1; it will convert to : int x = flag ? SafeInt<unsigned int>(y) : SafeInt<unsigned int>(-1); Correct way: int x = flag ? (int) SafeInt<unsigned int>(y) : -1; SafeInt Class 59
C++14 • Covers some additional C/C++ issues like INT30-C, “Ensure that unsigned integer operations do not wrap” 1 #include <boost/safe_numeric/safe_integer.hpp> 2 using namespace boost::numeric; 3 safe<int> f(safe<int> x, safe<int> y){ 4 return x + y; // throw exception if correct 5 // result cannot be returned 6 } Boost Safe Numeric Library 60
1 #ifdef TEST // using C++ on test platform 2 #include <cstdint> 3 #include <safe_integer.hpp> 4 #include <cpp.hpp> 5 typedef safe_t<std::int16_t> int16_t; 6 typedef safe_t<std::int32_t> int32_t; 7 #else // using C on embedded platform 8 typedef int int16_t; 9 typedef long int32_t; 10 #endif Boost Safe Numeric Library 61
with proper ranges • Convert types with the same singness and not less size • Use special compiler options that detect integer overflow • Try template classes that handle overload correctly Conclusion 63