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

Compare with Current View Page History

« Previous Version 30 Next »

Wide characters will contain null bytes if taken from the ASCII character set. As a result, using narrow character functions that rely on null-byte termination can lead to obtuse behavior. Likewise, a narrow character string that is properly null-terminated might not be considered so in a wide character function. Improper use of narrow and wide character strings could result in buffer overflows or data truncation.

Noncompliant Code Example (Using strncpy() instead of wcsncpy())

This example uses strncpy(), which copies, at most, 10 wide characters but will stop copying after it encounters a null byte. Because wide characters can contain null bytes, the code can stop copying prematurely. It is important to recognize that many narrow string functions are byte functions and so can terminate prematurely.

#include <stddef.h>
#include <string.h>
 
void func(void) {
  wchar_t wide_str1[]  = L"0123456789";
  wchar_t wide_str2[] =  L"0000000000";

  strncpy(wide_str2, wide_str1, 10);
}

Noncompliant Code Example (Using wcsncpy() instead of strncpy())

In most implementations, wide characters span multiple narrow characters. The wcsncpy() function copies, at most, 10 wide characters, which is greater than the number of bytes allocated to narrow_str1. As a result, it will write the first 10 bytes of narrow_str1 into narrow_str2 and then continue padding with L'\0' null wide characters until 10 wide characters have been written.

Note that wcsncpy() does not perform null termination if the source string contains more wide characters than the destination. Consequently, it is possible for an attacker to exploit such a vulnerability by passing a maliciously crafted string to wcsncpy(). If the code is intended to copy a certain number of bytes, it can overflow the buffer by writing multiple bytes because wcsncpy() measures copying by wide characters, not by bytes.

#include <wchar_t.h>
 
void func(void) {
  char narrow_str1[] = "0123456789";
  char narrow_str2[] = "0000000000";

  wcsncpy(narrow_str2, narrow_str1, 10);
}

Implementation Details

The C Standard recognizes wchar_t[] and char[] as distinct types. As a result, many compilers will produce a warning if the inappropriate function is used. For example, the following warnings were generated when the second noncompliant example was compiled with no flags in GCC on a Linux i686 platform:

warning: passing arg 1 of `wcsncpy' from incompatible pointer type
warning: passing arg 2 of `wcsncpy' from incompatible pointer type

Similar warnings were issued by the compiler for the first noncompliant example with respect to the arguments of the strncpy function instead. Because these are just warnings, the compiled code can still be run. When run on the i686 Linux platform, both noncompliant code examples exhibited buffer overflows.

Compliant Solution

This compliant solution uses the proper-width functions. Using wcsncpy() for wide character strings and strncpy() for narrow character strings ensures that data is not truncated and buffer overflow does not occur.

#include <stddef.h>
#include <string.h>
#include <wchar.h>
 
void func(void) {
  wchar_t wide_str1[] = L"0123456789";
  wchar_t wide_str2[] = L"0000000000";
  /* Use of proper-width function */ 
  wcsncpy(wide_str2, wide_str1, 10);

  char narrow_str1[] = "0123456789";
  char narrow_str2[] = "0000000000";
  /* Use of proper-width function */ 
  strncpy(narrow_str2, narrow_str1, 10);
}

Noncompliant Code Example (strlen())

In this noncompliant code example, the strlen() function is used to determine the size of a wide character string:

#include <stddef.h>
#include <stdlib.h>
#include <string.h>
 
void func(void) {
  wchar_t wide_str1[] = L"0123456789";
  wchar_t *wide_str2 = (wchar_t *)malloc(strlen(wide_str1) + 1);
  if (wide_str2 == NULL) {
    /* Handle error */
  }

  /* ... */
  free(wide_str2);
  wide_str2 = NULL;
}

The strlen() function counts the number of characters in a null-terminated byte string preceding the terminating null byte. However, wide characters can contain null bytes, particularly when taken from the ASCII character set, as in this example. As a result, the strlen() function will return the number of bytes preceding the first null byte in the string. 

Compliant Solution

This compliant solution correctly calculates the number of bytes required to contain a copy of the wide string (including the termination character):

#include <stddef.h>
#include <stdlib.h>
#include <wchar.h>
 
void func(void) {
  wchar_t wide_str1[] = L"0123456789";
  wchar_t *wide_str2 = (wchar_t *)malloc(
    (wcslen(wide_str1) + 1) * sizeof(wchar_t));
  if (wide_str2 == NULL) {
    /* Handle error */
  }
  /* ... */

  free(wide_str2);
  wide_str2 = NULL;
}

Risk Assessment

Failure to use the proper-width string functions can lead to buffer overflows and the execution of arbitrary code by an attacker.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

STR38-C

High

Likely

Low

P27

L1

Automated Detection

Modern compilers recognize the difference between a char * and a wchar_t *, so compiling code that violates this rule will generate warnings. It is feasible to have automated software that recognizes functions of improper width and replaces them with functions of proper width (that is, software that uses wcsncpy() when it recognizes that the parameters are of type wchar_t *).

Related Vulnerabilities

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


 

  • No labels