Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Защищенность целочисленных типов в C++

Защищенность целочисленных типов в C++

Доклад независимого эксперта Игоря Собинова для PDUG-секции на PHDays 8.

More Decks by Positive Development User Group

Other Decks in Technology

Transcript

  1. Заголовок • Introduction • Integer types and intervals • Integer

    Conversions • Integer Promotions • Mitigations • Conclusion and References Agenda 2
  2. Заголовок • Source of integer overflow • Types and kinds

    of integer overflow • Integer overflow mitigation Integer Overflow: Introduction 3
  3. Заголовок • Buffer overflow: buffer length calculation can result in

    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
  4. Заголовок CVE-2018-8781: Integer overflow in Linux kernel(DisplayLink driver) allows user

    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
  5. Заголовок int8_t x = 127, y = 2, z =

    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
  6. Заголовок uint8_t x = 129; int8_t y = x; //

    the following silently produces // a value of -127 Integer security: Example 8
  7. Заголовок How many times will this loop execute? unsigned char

    half_limit = 150; for (unsigned char i = 0; i < 2 * half_limit; ++i) { // do something; } С++ Secure Coding 10
  8. Заголовок • Introduction • Integer types and intervals • Integer

    Conversions • Integer Promotions • Mitigations • Conclusion and References Agenda 12
  9. Заголовок C++ doesn’t have any built-in range check for integers

    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
  10. Заголовок • Signed: signed integer ranges from -2n-1 through 2n-1-1.

    • 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
  11. Заголовок Addition of two 8 bit variables: Not 271 but

    15 С++ Secure Coding: The secret of 25u - 50 17
  12. Заголовок • Introduction • Integer types and intervals • Integer

    Conversions • Integer Operations • Mitigations • References Agenda 18
  13. Заголовок Type conversions occur explicitly in C++ as the result

    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
  14. Заголовок Integer promotions require the promotion of each variable (c1

    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
  15. Заголовок Unsigned Integer Conversions • Conversions of smaller unsigned integer

    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
  16. Заголовок When signed integer types are converted to the corresponding

    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
  17. Заголовок int i = -3; unsigned short u; u =

    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
  18. Заголовок An integer overflow occurs when an integer is increased

    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
  19. Заголовок int i = INT_MAX; // 2,147,483,647 i++; std::cout <<

    "i=" << i; //-2,147,483,648 unsigned int j = UINT_MAX; // 4,294,967,295; j++; std::cout<< "j=" <<j //0 Integer overflow example 25
  20. Заголовок i = INT_MIN; // -2,147,483,648; i--; std::cout << "i="

    << i; //2,147,483,647 j = 0; j--; std::cout << "j=" << j; //4,294,967,295 Integer overflow example 26
  21. Заголовок char cresult, c1, c2; c1 = 100; c2 =

    90; cresult = c1 + c2; //-66 unsigned int l = UINT_MAX; char c = -1; if (c == l) std::cout << "-1 = 4,294,967,295?"; Truncation example 27
  22. Заголовок • Introduction • Integer types and intervals • Integer

    Conversions • Integer Operations • Mitigations • Conclusion and References Agenda 29
  23. Заголовок Integer operations can result in errors and unexpected values:

    • 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
  24. Заголовок Unsigned Multiplication if (OperandSize == 8) { AX =

    AL * SRC; //Product of 8-bit operands is stored in 16-bit destination registers else { if (OperandSize == 16) { DX:AX = AX * SRC; //Product of 16-bit operands is stored in 32-bit destination //registers } else { // OperandSize == 32 Product of 32-bit operands is stored in 64-bit destination //registers EDX:EAX = EAX * SRC; } } Integer Operations 31
  25. Заголовок Upcasting: Cast both operands to an integer with at

    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
  26. Заголовок void* AllocBlocks(size_t cBlocks) { // allocating no blocks is

    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
  27. Заголовок void* AllocBlocks(size_t cBlocks) { // allocating no blocks is

    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
  28. Заголовок An integer overflow condition occurs when the minimum integer

    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
  29. Заголовок • Introduction • Integer types and intervals • Integer

    Conversions • Integer Operations • Mitigations • References Agenda 36
  30. Заголовок Type Range Checking: External inputs should be evaluated to

    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
  31. Заголовок Types: One way to provide better type checking is

    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
  32. Заголовок size_t could be an issue: Extremely large object sizes

    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
  33. Заголовок RSIZE_MAX: the maximum size of a normal single object

    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
  34. Заголовок C++ exception handling does not allow recovery from •

    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
  35. Заголовок 1 sint operator /(unsigned int divisor) { 2 try

    { 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
  36. Заголовок Visual C++ generates a warning (C4244) when an integer

    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
  37. Заголовок /RTCc compiler option: Causes a run-time error when a

    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
  38. Заголовок -ftrapv option • Instructs the compiler to generate traps

    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
  39. Заголовок -fwrapv-pointer: This option instructs the compiler to assume that

    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
  40. Заголовок bool __builtin_add_overflow (type1 a, type2 b, type3 *res) family

    bool __builtin_sub_overflow (type1 a, type2 b, type3 *res) family bool __builtin_mul_overflow (type1 a, type2 b, type3 *res) family 1 int x1 = -1073741826, y1 = -1073741826; 2 int z1 = x1 + y1; 3 if (__builtin_add_overflow(x1, y1, &temp)) 4 std::cout << "overflow detected"; 5 6 std::count << z; GCC Mitigations 49
  41. Заголовок How to check unsigned integers: • A + B

    > 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
  42. Заголовок SEI (Software Engineering Institute) published the guide of how

    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
  43. Заголовок Compliant Solution 1 #include <limits.h> 2 void f(signed int

    si_a, signed int si_b) { 3 signed int sum; 4 if (((si_b > 0) && (si_a > (INT_MAX - si_b))) || 5 ((si_b < 0) && (si_a < (INT_MIN - si_b)))) { 6 /* Handle error */ 7 } 8 sum = si_a + si_b; } Use correct checking for signed integers 52
  44. Заголовок 1 if (!((rhs ^ lhs) < 0)) { 2

    //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
  45. Заголовок 12 else { 13 //two positives 14 if(MaxInt() -

    lhs < rhs) { 15 throw ERROR_ARITHMETIC_OVERFLOW; 16 } 17 //Ok 18 } 19 } 20 //else overflow not possible 21 return lhs + rhs; Use correct checking for signed integers 54
  46. Заголовок The SafeInt class protects against integer overflow in mathematical

    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
  47. Заголовок 1 int main(int argc, char *const *argv) { 2

    try{ 3 SafeInt<unsigned long> s1(strlen(argv[1])); 4 SafeInt<unsigned long> s2(strlen(argv[2])); 5 char *buff = (char *) malloc(s1 + s2 + 1); 6 strcpy(buff, argv[1]); 7 strcat(buff, argv[2]); 8 } 9 catch(SafeIntException err) { 10 abort(); } SafeInt Class 56
  48. Заголовок SafeInt advantages: • Portability - does not depend on

    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
  49. Заголовок SafeInt issues: • Many binary operators do not support

    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
  50. Заголовок SafeInt issues: • SafeInt<uint>((uint)~0) > -1 is true but

    ((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
  51. Заголовок • Proposal for the C++ Standard Library • Required

    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
  52. Заголовок How to test C/C++ programs with boost numeric library

    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
  53. Заголовок • Introduction • Integer types and intervals • Integer

    Conversions • Integer Operations • Mitigations • Conclusion and References Agenda 62
  54. Заголовок To mitigate integer overflow issues: • Use proper types

    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
  55. Заголовок Books: “Secure coding: Principles and Practices” Kenneth van Wyk,

    Mark Graff “Secure Coding: Principles and Practices” O'Reilly Media 2009 65
  56. Заголовок Books: “Secure coding in C and C++” Robert C.

    Seacord “Secure Coding in C and C++” (2nd Edition) Addison-Wesley 2005 66
  57. Заголовок Igor Sobinov: Software developer for Linux, Windows, Embedded Will

    be glad to receive feedbacks: • [email protected] • Skype:igor.sobinov About Author 67