Integral Security

C++, integer errors, and software vulnerability


November 03, 2006
URL:http://www.drdobbs.com/security/integral-security/193501774

In 2005, I wrote that "Integers represent a growing and underestimated source of vulnerabilities in C and C++ programs" as the lead sentence in the "Integer Security" chapter of Secure Coding in C and C++. This prediction has been borne out in a recent study published by MITRE on the types of errors that lead to publicly reported vulnerabilities. "Integer overflows, barely in the top 10 overall in the past few years, are in the top 3 for OS vendor advisories".

An Integer Story

A vulnerability in bash versions 1.14.6 and earlier that resulted in the release of CERT Advisory CA-1996-22 provides an example of a programming error resulting from the incorrect use of integers.

The GNU Project's Bourne Again Shell (bash) is a drop-in replacement for the UNIX Bourne shell (/bin/sh). It has the same syntax as the standard shell but provides additional functionality such as job control, command-line editing, and history. Although bash can be compiled and installed on almost any UNIX platform, its most prevalent use is on Linux, where it has been installed as the default shell for most applications. The bash source code is freely available from many sites on the Internet.

There is a variable declaration error in the yy_string_get() function in the parse.y module of the bash source code:

static int yy_string_get() {
  register char *string;
  register int c;
  string = bash_input.location.string;
  c = EOF;
  /* If the string doesn't exist, or is empty, EOF found. */
  if (string && *string) {
      c = *string++;
      bash_input.location.string = string;
    }
  return (c);
}

This function is responsible for parsing the user-provided command line into separate tokens. The error involves the variable string, which has been declared to be of type char *.

The string variable is used to traverse the character string containing the command line to be parsed. As characters are retrieved from this pointer, they are stored in a variable of type int. For compilers in which the char type defaults to signed char, this value is sign-extended when assigned to the int variable. For character code 255 decimal (-1 in two's complement form), this sign extension results in the value -1 being assigned to the integer.

However, -1 is used in other parts of the parser to indicate the end of a command. Thus, the character code 255 decimal (377 octal) serves as an unintended command separator for commands given to bash via the -c option. For example:

bash -c 'ls\377who'

(where \377 represents the single character with value 255 decimal) will execute two commands, ls and who.

This example is interesting in that the vulnerability is entirely the result of an error in handling an integer value. More commonly, integer errors result in vulnerabilities by causing an exploitable buffer overflow.

Integer Errors

There are three common integer errors that lead to software vulnerabilities: overflow, sign errors, and truncation.

With few exceptions, compilers do not generally issue diagnostics for potential integer errors or report these errors at runtime. The Visual C++ .NET 2003 compiler, for example, does generates a compiler warning (C4244) when an integer value is assigned to a smaller integer type. At warning level 1, a warning will be issued if a value of type __int64 is assigned to a variable of type unsigned int. At warning level 3 and 4, a "possible loss of data" warning is issued if an integer type is converted to a smaller integer type.

As a result, preventing integer errors is primarily left to programmers and is impossible without a deep understanding of integer behavior in C and C++. It is apparent in the example below that the developer made some effort to prevent an integer overflow from occurring when multiplying cBlocks by 16:

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;
}

Unfortunately, this example contains an incorrect assumption about integer behavior. The developer has assumed that because the result of multiplication is being stored in a 64-bit unsigned long long integer that the multiplication will result in a 64-bit value. This is not the case, however. To be compliant with the language standard, multiplying two 32-bit numbers in this context must yield a 32-bit result. The resulting value is zero-extended to create a 64-bit value. As a result, any overflow resulting from this multiplication will remain undetected, and the value of alloc is always less than UINT_MAX.

A good source of information on integral security is the CERT Secure Coding Standards for C and C++. The rationale for these standards is described in NIST Special Publication 500-262.

Mitigation Strategies

Mitigation strategies for integer errors include range checking, compiling with high warning levels and eliminating all warnings, testing, reviews, and safe integer operations.

Safe integer operations typically involve using a library or class that provides safe integer operations for integer values that originate from untrusted sources and are used as an array index, in any pointer arithmetic, as a length or size of an object, as the bound of an array (for example, a loop counter), as an argument to a memory allocation function, or in security critical code.

SafeInt

SafeInt is a C++ template class written by David LeBlanc. SafeInt throws an exception if the results of an integer operation cannot be represented in the specified type. The class is declared as a template, so it can be used with any integer type. Every operator has been overridden except for the subscript operator[] so that operators can be used in normal arithmetic expressions.

SafeInt fails to provide correct integer promotion behavior, but the greatest limitation of SafeInt is that it cannot be used with C applications. Because operators cannot be overloaded in C, safe integer solutions are not as easy to use.

CERT Integer Library

The CERT Coordination Center has recently released a secure integer library for the C Programming Language. The library is available for download from the CERT/CC Secure Coding Initiative web page

The purpose of the library is to provide a collection of utility functions that can assist software developers in writing C programs that are free from integer problems such as integer overflow, integer truncation, and sign errors that are a common source of software vulnerabilities.

Functions have been provided for all integer operations subject to overflow such as addition, subtraction, multiplication, division, unary negation, and so on) for int, long, long long, and size_t integers. The following example illustrates how the library can be used to add two signed long integer values:

long retsl, xsl, ysl;
	xsl = LONG_MAX;
	ysl = 0;
	retsl = addsl(xsl,ysl);

For short integer types (char and short) it is necessary to truncate the result of the addition using one of the safe conversion functions provided. For example:

char retsc, xsc, ysc;
	xsc = SCHAR_MAX;
	ysc = 0;
	retsc = si2sc(addsi(xsc, ysc));

For error handling, the secure integer library uses the mechanism for runtime-constraint handling defined by ISO/IEC TR 24731.

The implementation uses the high-performance algorithms defined by Henry S. Warren in the book Hacker's Delight.

Conclusions

Integer vulnerabilities result from lost or misrepresented data. The key to preventing these vulnerabilities is to understand the nuances of integer behavior in C and C++ and carefully apply this knowledge in the design and implementation of your systems.

Consider using safe integer operations to eliminate exception conditions, focusing on integers used as indices (or other pointer arithmetic), lengths, sizes, and loop counters.

If integer type range checking is properly applied and safe integer operations are used for values that can pass out of range (particularly due to external manipulation), it is possible to prevent vulnerabilities resulting from integer range errors.


Robert Seacord is a Senior Vulnerability Analyst for CERT/CC, where he leads the secure coding initiative, including the development of secure coding standards for C and C++. He is also the author of three books, including Secure Coding in C and C++ .

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.