Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0

...

Noncompliant Code Example (Off-by-One Error)

Wiki MarkupThis noncompliant code example demonstrates what is commonly referred to as an _off-by-one_ error \ [[Dowd 2006|AA. Bibliography#Dowd 06]\]. 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#FFCCCC
langc
char dest[ARRAY_SIZE];
char src[ARRAY_SIZE];
size_t i;
/* ... */
for (i=0; src[i] && (i < sizeof(dest)); i++) {
  dest[i] = src[i];
}
dest[i] = '\0';
/* ... */

...

Code Block
bgColor#FFcccc
langc
int main(int argc, char *argv[]) { /* ... */ }

...

Command-line arguments are passed to {{main()}} as pointers to null-terminated byte strings in the array members {{argv\[0\]}} through {{argv\] through argv[argc-1\]}}. If the value of {{argc}} is greater than zero, the string pointed to by {{argv\[0\]}} is, by convention, the program name. If the value of {{argc}} is greater than one, the strings referenced by {{argv\argv[1\]}} through {{argv\[argc-1\]}} are the actual program arguments.

Wiki MarkupVulnerabilities can occur when inadequate space is allocated to copy a command-line argument or other program input. In this noncompliant code example, the contents of {{argv\[0\]}} can be manipulated by an attacker to cause a buffer overflow:

Code Block
bgColor#FFcccc
langc
int main(int argc, char *argv[]) {
  /* ... */
  char prog_name[128];
  strcpy(prog_name, argv[0]);
  /* ... */
}

Compliant Solution (argv) (strcpy())

...

The {{strlen()}} function can be used to determine the length of the strings referenced by {{argv\[0\]}} through {{argv\[argc-1\]}} so that adequate memory can be dynamically allocated. Note that care must be taken to avoid assuming 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 = (char *)malloc(strlen(name) + 1);
  if (prog_name != NULL) {
    strcpy(prog_name, name);
  }
  else {
    /* Failed to allocate memory - recover */
  }
  /* ... */
}

...

Compliant Solution (argv) (strcpy_s())

...

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 */
  }
  /* ... */
}

...

Compliant Solution (argv) (memcpy())

...

The C standard {{memcpy()}} function provide 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 */
  }
  /* ... */
}

...

Compliant Solution (argv)

Wiki MarkupIf 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 must be taken to avoid assuming 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 *prog_name = argv[0] ? argv[0] : "";
  size_t prog_size;
  /* ... */
}

...

Tool

Version

Checker

Description

Section

LDRA tool suite

Include Page
c:LDRA_Vc:
LDRA_V

 

 

Section

Fortify SCA

Section

V. 5.0

 

 

Section

Splint

Include Page
c:Splint_Vc:
Splint_V

 

 

Section

Compass/ROSE

 

 

Section

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

Section

Klocwork

Include Page
c:Klocwork_Vc:
Klocwork_V

 

 

Related Vulnerabilities

...

[CVE-2009-1252|http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2009-1252] results from a violation of this rule. The Network Time Protocol 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|http://xorl.wordpress.com/ 2009/06/10/freebsd-sa-0911-ntpd-remote-stack-based-buffer-overflows/]\].

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

...

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

Bibliography

...

\[[Dowd 2006|AA. Bibliography#Dowd 06]\] Chapter ] Chapter 7, "Program Building Blocks" (Loop Constructs 327-336) \[
[Seacord 2005a|AA. Bibliography#Seacord 05]\] Chapter 2, "Strings" \
[[xorl 2009|AA. Bibliography#xorl 2009] \] ["FreeBSD-SA-09:11: NTPd Remote Stack Based Buffer Overflows"|http://xorl.wordpress.com/2009/06/10/freebsd-sa-0911-ntpd-remote-stack-based-buffer-overflows/]

...

      07. Characters and Strings (STR)      STR32-C. Null-terminate byte strings as required