Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The size_t type is the unsigned integer type of the result of the sizeof operator. Variables of type size_t are guaranteed to be of sufficient precision to represent the size of an object. The limit of size_t is specified by the SIZE_MAX macro.

Wiki MarkupThe type {{size_t}} generally covers the entire address space.   \[[TR 24731-1|AA. C References#ISO/IEC TR 24731-1-2007]\] introduces a new type {{rsize_t}}, defined to be {{size_t}} but explicitly used to hold the size of a single object.  In code that documents this purpose by using the type {{rsize_t}}, the size of an object can be checked to verify that it is no larger than {{RSIZE_MAX}}, the maximum size of a normal single object, which provides additional input validation for library functions.  See \[[STR00-A. Use TR 24731 for remediation of existing string manipulation code]\] for additional discussion of TR 24731-1The C Standard, Annex K (normative), "Bounds-checking interfaces," introduces a new type, rsize_t, defined to be size_t but explicitly used to hold the size of a single object [Meyers 2004]. In code that documents this purpose by using the type rsize_t, the size of an object can be checked to verify that it is no larger than RSIZE_MAX, the maximum size of a normal single object, which provides additional input validation for library functions. See STR07-C. Use the bounds-checking interfaces for string manipulation for additional discussion of C11 Annex K.

Any variable that is used to represent the size of an object, including integer values used as sizes, indices, loop counters, and lengths, should be declared as rsize_t, if available, otherwise . Otherwise, it should be declared size_t.

...

Noncompliant Code Example

In this non-compliant noncompliant code example, the dynamically allocated buffer referenced by p overflows for values of n > INT_MAX.:

Code Block
bgColor#FFcccc
langc

char *copy(size_t n, const char *c_str) {
  int i;
  char *p;

  if (n == 0) {
    /* Handle unreasonable object size error */
  }
  p = (char *)malloc(n);
  if (p == NULL) {
    return NULL; /* HandleIndicate malloc failure */
  }
  for ( i = 0; i < n; ++i ) {
    p[i] = *c_str++;
  }
  return p;
}

char *p = copy(9,/* ... */

char c_str[] = "hi there");

...

char *p = copy(sizeof(c_str), c_str);

Signed integer overflow causes undefined behavior. The following are two possible conditions under which this code constitutes a serious vulnerability:

...

sizeof(size_t)

...

==

...

sizeof(int)

...

The unsigned n may contain a value greater than INT_MAX. Assuming quiet wraparound on signed overflow, the loop executes n times because the comparison i < n is an unsigned comparison. Once i is incremented beyond INT_MAX, i takes on negative values starting with (INT_MIN). Consequently, the memory locations referenced by p[i] precede the memory referenced by p, and a write outside array bounds occurs.

...

sizeof(size_t)

...

>

...

sizeof(int)

...

For values of n where 0 < n <= INT_MAX, the loop executes n times, as expected.

For values of n where INT_MAX < n <= (size_t)INT_MIN, the loop executes INT_MAX times. Once i becomes negative, the loop stops, and i remains in the range 0 through INT_MAX.

For values of n where (size_t)INT_MIN < n <= SIZE_MAX, i wraps and takes the values INT_MIN to INT_MIN + (n - (size_t)INT_MIN - 1). Execution of the loop overwrites memory from p[INT_MIN] through p[INT_MIN + (n - (size_t)INT_MIN - 1)].

Compliant Solution (C11, Annex K)

Note that in a preemptive multithreaded program, only one thread is in the infinite loop, so it is still significant that out-of-bounds memory is changed.

...

Declaring i to be of type rsize_t eliminates the possible integer overflow condition (in this example).   Also, the argument n is changed to be of type rsize_t to document additional validation in the form of a check against RSIZE_MAX.:

Code Block
bgColor#ccccff
langc

char *copy(rsize_t n, const char *c_str) {
  rsize_t i;
  char *p;

  if (n == 0 || n > RSIZE_MAX) {
    /* Handle unreasonable object size error */
  }
  p = (char *)malloc(n);
  if (p == NULL) {
    return NULL;  /* HandleIndicate malloc failure */
  }
  for ( i = 0; i < n; ++i ) {
    p[i] = *c_str++;
  }
  return p;
}

/* ... */

char c_str[] = "hi there";
char *p = copy(9, "hi there"sizeof(c_str), c_str);

...

Noncompliant Code Example

In this non-compliant noncompliant code example, an integer overflow is specifically checked for by checking if length + 1 == 0 (that is, integer wrap has occurred). If the test passes, the value of length is read from a network connection and passed as an argument to a wrapper to malloc() is called to allocate the appropriate data block (this is a common idiom). In a program compiled using an ILP32 compiler. Provided that the size of an unsigned long is equal to the size of an unsigned int, and both sizes are equal to or smaller than the size of size_t, this code runs as expected, but in an LP64 environment an integer overflow can occur, because length is now a 64-bit value. Tthe result of the expression, however, is truncated to 32-bits . However, if the size of an unsigned long is greater than the size of an unsigned int, the value stored in length may be truncated when passed as an argument to alloc(), because it takes an unsigned int argument.  Both read functions return zero on success and nonzero on failure.

Code Block
bgColor#FFcccc
langc

void *alloc(unsigned int blocksize) {
  return malloc(blocksize);
}

int read_counted_string(int fd) {
  unsigned long length;
  unsigned char *data;

  if (read_integer_from_network(fd, &length) < 0) {
    return -1;
  }

  data = if (unsigned char*)alloc(length + 1+1);
  if (data == 0NULL) {
    return -1;  /* handleIndicate integer overflowfailure */
  }

  data = (unsigned char*)alloc(length + 1);

  if (read_network_data(fd, data, length) < 0) {
    free(data);
    return -1;
  }
  data[length] = '\0';

  /* ... */
  free( data);
  return 0;
}

Compliant Solution (C11, Annex K)

Declaring both length and the blocksize argument to alloc() as rsize_t eliminates the possibility of truncation. This compliant solution assumes that read_integer_from_network() and read_network_data() can also be modified to accept a length argument of type pointer to rsize_t and rsize_t, respectively. If these functions are part of an external library that cannot be updated, care must be taken when casting length into an unsigned long to ensure that integer truncation does not occur.

Code Block
bgColor#ccccff
langc

void *alloc(rsize_t blocksize) {
  if (blocksize == 0 || blocksize > RSIZE_MAX) {
    return NULL;  /* HandleIndicate errorfailure */
  }
  return malloc(blocksize);
}

int read_counted_string(int fd) {
  rsize_t length;
  unsigned char *data;

  if (read_integer_from_network(fd, &length) < 0) {
    return -1;
  }

  data if= (unsigned char*)alloc(length + 1+1);
  if (data == 0NULL) {
    return -1; /* handleIndicate integerfailure overflow */
  }

  data = (unsigned char*)alloc(length + 1);

  if (read_network_data(fd, data, length) < 0) {
    free(data);
    return -1;
  }
  data[length] = '\0';

  /* ... */
  free( data);
  return 0;
}

Risk Assessment

The improper calculation or manipulation of an object's size can result in exploitable vulnerabilities.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

INT01-

A

2 (medium)

2 (probable)

2 (medium)

P8

L2

C

Medium

Probable

Medium

P8

L2

Automated Detection

Tool

Version

Checker

Description

Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-INT01
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

LANG.TYPE.BASIC

Basic numerical type used
Compass/ROSE



Can detect violations of this recommendation. In particular, it catches comparisons and operations where one operand is of type size_t or rsize_t and the other is not

Splint
Include Page
Splint_V
Splint_V



Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

Wiki Markup
\[[ISO/IEC 9899-1999|AA. C References#ISO/IEC 9899-1999]\] Section 7.17, "Common definitions <stddef.h>"
\[[ISO/IEC 9899-1999|AA. C References#ISO/IEC 9899-1999]\] Section 7.20.3, "Memory management functions"
\[[ISO/IEC TR 24731-1-2007|AA. C References#ISO/IEC TR 24731-1-2007]\]

Related Guidelines

Bibliography


...

Image Added Image Added Image AddedINT00-A. Understand the data model used by your implementation(s)      04. Integers (INT)       INT02-A. Understand integer conversion rules