Versions Compared

Key

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

Copying data to a buffer that is not large enough to hold that data results in a buffer overflow. While not limited to null-terminated byte strings (NTBS), buffer overflows often occur when manipulating NTBS data. To prevent such errors, limit either limit copies either through truncation or, preferably, ensure that the destination is of sufficient size to hold the character data to be copied and the null-termination character. (See recommendation STR03-C. Do not inadvertently truncate a null-terminated byte string.)

...

This noncompliant code example demonstrates what is commonly referred to as commonly called an off-by-one error [Dowd 2006]. The loop copies data from src to dest. However, the null terminator may incorrectly be written one byte past the end of dest because the loop does not account for the null-termination character that must be appended to dest.

...

Code Block
bgColor#ccccff
langc

int main(int argc, char *argv[]) {
  /* Be prepared for argv[0] to be null */
  const char* const name = argv[0] ? argv[0] : "";
  char *prog_name = (char *)malloc(strlen(name) + 1);
  if (prog_name != NULL) {
    strcpy(prog_name, name);
  }
  else {
    /* Failed to allocate memory - recover */
  }
  /* ... */
}

...

The strcpy_s() function provides additional safeguards, including accepting the size of the destination buffer as an additional argument. (See recommendation STR07-C. Use the bounds-checking interfaces for remediation of existing string manipulation code.) Do not assume that argv[0] is non-null.

Code Block
bgColor#ccccff
langc

int main(int argc, char *argv[]) {
  /* Be prepared for argv[0] to be null */
  const char* const name = argv[0] ? argv[0] : "";

  char * prog_name;
  size_t prog_size;

  prog_size = strlen(name) + 1;
  prog_name = (char *)malloc(prog_size);

  if (prog_name != NULL) {
    if (strcpy_s(prog_name, prog_size, name)) {
      /* Handle strcpy_s() error */
    }
  }
  else {

    /* Failed to allocate memory - recover */
  }
  /* ... */
}

The strcpy_s() function can be used to copy data to or from dynamically allocated memory or a statically allocated array. If insufficient space is available, strcpy_s() returns an error.

...

The C standard memcpy() function provide provides a similar capability to strcpy_s(), but is universally available. Note that care must be taken to avoid assuming that argv[0] is non-null. Note also that memcpy must not be called with a null pointer even when the second (size) argument is zero.

Code Block
bgColor#ccccff
langc

int main(int argc, char *argv[]) {
  /* Be prepared for argv[0] to be null */
  const char* const name = argv[0] ? argv[0] : "";

  char *prog_name;
  size_t prog_size;

  prog_size = strlen(name) + 1;
  prog_name = (char *)malloc(prog_size);

  if (prog_name != NULL) {
    memcpy(prog_name, name, prog_size);
  }
  else {
    /* Failed to allocate memory - recover */
  }
  /* ... */
}

...

If an argument is not going to be modified or concatenated, there is no reason to make a copy of the string. Not copying a string is the best way to prevent a buffer overflow , and is also the most efficient solution. Note that care Care must be taken to avoid assuming that argv[0] is non-null.

...

In this example, name refers to an external string; it could have originated from user input, or from the file system, or from the network. The program constructs a filename file name from the string in preparation for opening the file.

...

However, because the sprintf() function makes no guarantees regarding the length of the string generated, a sufficiently - long string in name could generate a buffer overflow.

...

The buffer overflow can be prevented by providing a precision length to the %s specifier. The value 123 ensures that filename can contain the first 123 characters of name, the " .txt " extension, and the null terminator.

...

section

Splint

can

Can detect violations of the rule. However, it is unable to handle cases involving strcpy_s() or manual string copies such as the one in the first example.

Klocwork

Tool

Version

Checker

Description

LDRA tool suite

Include Page
LDRA_V
LDRA_V

 

 

section

Fortify SCA

section

V. 5.0

 

 

Section
Include Page
Splint_V
Splint_V

 

 

section

Compass/ROSE

 

 

Section
Section
Include Page
Klocwork_V
Klocwork_V

 

 

...

CVE-2009-1252 results from a violation of this rule. The Network Time Protocol (NTPd), before versions 4.2.4p7 and 4.2.5p74, contained calls to sprintf that allow an attacker to execute arbitrary code by overflowing a character array [xorl 2009].

...

CERT C++ Secure Coding Standard: STR31-CPP. Guarantee that storage for character arrays has sufficient space for character data and the null terminator

ISO/IEC 9899:19992011 Section 7.1.1, "Definitions of terms," Section 7.2124, "String handling <string.h>," Section 5.1.2.2.1, "Program startup," and Section 7.2022.4.56, "The getenv function"

ISO/IEC TR 17961 (Draft) Using a tainted value to write to an object using a formatted input or output function [taintformatio]

ISO/IEC TR 24772 "CJM String Termination," "XYW Buffer Overflow in Stack," , and "XYB Buffer Overflow in Heap"

...

MITRE CWE: CWE-120, "Buffer Copy without Checking Size of Input ('"Classic Buffer Overflow'")"

MITRE CWE: CWE-193, "Off-by-one One Error"

Bibliography

[Dowd 2006] Chapter 7, "Program Building Blocks" (Loop Constructs 327-336327–336)
[Seacord 2005a] Chapter 2, "Strings"
[xorl 2009] "FreeBSD-SA-09:11: NTPd Remote Stack Based Buffer Overflows"

...