You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 107 Next »

Many library functions accept a string or wide string argument with the constraint that the string they receive is properly null-terminated. Passing a character sequence or wide character sequence that is not null-terminated to such a function can result in accessing memory that is outside the bounds of the object.  Do not pass a character sequence or wide character sequence that is not null-terminated to a library function that expects a string or wide string argument. 

Noncompliant Code Example

This code example is noncompliant because the character sequence str will not be null-terminated when passed as an argument to printf().  See STR11-C. Do not specify the bound of a character array initialized with a string literal.

char str[3] = "abc";
printf("%s\n", str);

Compliant Solution

This compliant solution does not specify the bound of a character array in the array declaration. If the array bound is omitted, the compiler allocates sufficient storage to store the entire string literal, including the terminating null character.

char str[3] = "abc";
printf("%s\n", str);

Noncompliant Code Example

This code example is noncompliant because the wide character sequence cur_msg will not be null-terminated when passed to wcslen(). This will occur if lessen_memory_usage() is invoked while cur_msg_size still has its initial value of 1024.

 

wchar_t *cur_msg = NULL;
size_t cur_msg_size = 1024;
size_t cur_msg_len = 0;

void lessen_memory_usage(void) {
  wchar_t *temp;
  size_t temp_size;

  /* ... */

  if (cur_msg != NULL) {
    temp_size = cur_msg_size / 2 + 1;
    temp = realloc(cur_msg, temp_size * sizeof(wchar_t));
    // temp & cur_msg might not be null-terminated
    if (temp == NULL) {
      /* Handle error */
    }

    cur_msg = temp;
    cur_msg_size = temp_size;
    cur_msg_len = wcslen(cur_msg); // error 
  }
}

Compliant Solution

In this compliant solution, cur_msg will always be null-terminated when passed to wcslen().

wchar_t *cur_msg = NULL;
size_t cur_msg_size = 1024;
size_t cur_msg_len = 0;

void lessen_memory_usage(void) {
  wchar_t *temp;
  size_t temp_size;

  /* ... */

  if (cur_msg != NULL) {
    temp_size = cur_msg_size / 2 + 1;
    temp = realloc(cur_msg, temp_size * sizeof(wchar_t));
    // temp & cur_msg might not be null-terminated
    if (temp == NULL) {
      /* Handle error */
    }

    cur_msg = temp;
    // cur_msg now properly null-terminated
    cur_msg[temp_size - 1] = L'\0'; 
    cur_msg_size = temp_size;
    cur_msg_len = wcslen(cur_msg); 
  }
}

Noncompliant Code Example (strncpy())

While the strncpy() function takes a string as input, it does not guarantee that the resulting value is still null-terminated. In the following noncompliant code example, if no null character is contained in the first n characters of the source array, the result will not be null-terminated. Passing a non-null-terminated character sequence to strlen() results in undefined behavior:

#include <string.h>
 
enum { STR_SIZE = 32 };
 
size_t func(const char *source) {
  char str[STR_SIZE];

  str[sizeof(str) - 1] = '\0';
  strncpy(str, source, sizeof(str));
  return strlen(str);
}

Compliant Solution (Truncation)

The correct solution depends on the programmer's intent. If the intent is to truncate a string, this solution can be used:

#include <string.h>
 
enum { STR_SIZE = 32 };
 
size_t func(const char *source) {
  char str[STR_SIZE];

  strncpy(str, source, sizeof(str) - 1);
  str[sizeof(str) - 1] = '\0';
  return strlen( str);
}

Compliant Solution (Copy without Truncation)

If the intent is to copy without truncation, this example copies the data and guarantees that the resulting array is null-terminated. If the string cannot be copied, it is handled as an error condition.

#include <string.h>
 
enum { STR_SIZE = 32 };
 
size_t func(const char *source) {
  char str[STR_SIZE];

  if (source) {
    if (strlen(source) < sizeof(str)) {
      strcpy(str, source);
    } else {
      /* Handle string-too-large */
    }
  } else {
    /* Handle null pointer */
  }
  return strlen(str);
}

Compliant Solution (strncpy_s(), C11 Annex K)

The C11 Annex K strncpy_s() function copies up to n characters from the source array to a destination array. If no null character was copied from the source array, then the nth position in the destination array is set to a null character, guaranteeing that the resulting string is null-terminated.

#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
  
enum { STR_SIZE = 32 };
  
size_t func(const char *source) {
  char a[STR_SIZE];

  if (source) {
    errno_t err = strncpy_s(a, sizeof(a), source, 5);
    if (err != 0) {
      /* Handle error */
    }
  } else {
    /* Handle null pointer */
  }
  return strlen_s(s, sizeof(a));
}

Risk Assessment

Failure to properly null-terminate a character sequence that is passed to a library function that expects a string can result in buffer overflows and the execution of arbitrary code with the permissions of the vulnerable process. Null-termination errors can also result in unintended information disclosure.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

STR32-C

High

Probable

Medium

P12

L1

Automated Detection

Tool

Version

Checker

Description

Compass/ROSE

 

 

Can detect some violations of this rule

Coverity6.5STRING_NULLFully Implemented

Klocwork

2024.3

NNTS

 

LDRA tool suite

9.7.1

600 S

Fully implemented

Related Vulnerabilities

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

Related Guidelines

CERT C++ Secure Coding StandardSTR32-CPP. Null-terminate character arrays as required
ISO/IEC TR 24772:2013String Termination [CMJ]
ISO/IEC TS 17961Passing a non-null-terminated character sequence to a library function that expects a string [strmod]
MITRE CWECWE-119, Failure to constrain operations within the bounds of an allocated memory buffer
CWE-170, Improper null termination

Bibliography

[Seacord 2013] Chapter 2, "Strings" 
[Viega 2005]Section 5.2.14, "Miscalculated NULL Termination"

 


 

 

 

  • No labels