Passing narrow string arguments to wide string functions or wide string arguments to narrow string functions can lead to unexpected and undefined behavior 151. Scaling problems are likely because of the difference in size between wide and narrow characters. (See ARR39-C. Do not add or subtract a scaled integer to a pointer.) Because wide strings are terminated by a null wide character and can contain null bytes, determining the length is also problematic.
Because wchar_t and char are distinct types, many compilers will produce a warning diagnostic if an inappropriate function is used. (See MSC00-C. Compile cleanly at high warning levels.)
Noncompliant Code Example (Wide Strings with Narrow String Functions)
This noncompliant code example incorrectly uses the strncpy() function in an attempt to copy up to 10 wide characters. However, because wide characters can contain null bytes, the copy operation may end earlier than anticipated, resulting in the truncation of the wide string
Wide characters may frequently contain null bytes if taken from the ASCII character set. As a result, using narrow-char functions which rely on null-byte termination may lead to obtuse behavior. Likewise, a narrow-char string which is properly null-terminated may not be considered so in a wide-char function. Improper use of narrow and wide character strings could result in buffer overflows.
Noncompliant Code Example (Using strncpy instead of wcsncpy)
The below example uses strncpy which will copy at most 10 bytes in this example, but will stop copying after it encounters a null-byte. Since wide-characters may contain null-bytes, it may stop copying prematurely. It is important to recognize that many narrow-string functions are byte functions, and thus may terminate prematurely.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#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 (
...
The below example uses wcsncpy, which will copy 10 wide-length characters. In most implementations, wide-characters span multiple narrow-characters. The wcsncpy function will copy at most 10 wide-characters, which is longer than 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.
Narrow Strings with Wide String Functions)
This noncompliant code example incorrectly invokes the wcsncpy() function to copy up to 10 wide characters from narrow_str1 to narrow_str2. Because narrow_str2 is a narrow string, it has insufficient memory to store the result of the copy and the copy will result in a buffer overflowIt should be noted that wcsncpy does not perform null-termination if the source string contains more wide-characters than the destination. As a result, 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 may overflow the buffer by writing multiple bytes as wcsncpy measures copying by wide-characters, not by bytes.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <wchar.h> void func(void) { char *narrow_str1[] = "012345678901234567890123456789"; char *narrow_str2[] = "0000000000"; wcsncpy(narrow_str2, narrow_str1, 10); |
Implementation Details
C99 recognizes wchar_t * and char * as distinct types. As a result, many compilers will yield a warning if the inappropriate function is used. For example, the following warnings were generated when the second non-compliant example was compiled with no flags in GCC on a Linux i686 platform:
| Code Block |
|---|
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 non-compliant example, with respect to the arguments of the strncpy function instead.
Since these are just warnings, the compiled code can still be run. When run on the i686 Linux platform mentioned above, both noncompliant code examples began copying information from out of the bounds of the arguments. This behavior is indicative a possible buffer overflow vulnerability.
Compliant Solution
} |
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 occurThe below example uses the appropriate-width function versions. Using wcsncpy for wide-char strings and strncpy for narrow-char strings will ensure that data is not truncated or overwriting extra memory.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#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:
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <stdlib.h> char *narrow_str1#include <string.h> void func(void) { wchar_t wide_str1[] = L"0123456789"; wchar_t *wide_str2 = (wchar_t*)malloc(strlen(wide_str1) + 1); char *narrow_str2 = "0000000000"; strncpy(narrow_str2, narrow_str1, 10); /* Use of proper-width function */ |
Risk Assessment
if (wide_str2 == NULL) {
/* Handle error */
}
/* ... */
free(wide_str2);
wide_str2 = NULL;
} |
The strlen() function determines the number of characters that precede the terminating null character. However, wide characters can contain null bytes, particularly when expressing characters 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 wide string.
Compliant Solution
This compliant solution correctly calculates the number of bytes required to contain a copy of the wide string, including the terminating null wide character:
| Code Block | ||||
|---|---|---|---|---|
| ||||
#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
Confusing narrow and wide character strings can result in buffer overflows, data truncation, and other defectsFailure to use the proper-width string functions can lead to buffer overflows and the execution of arbitrary code by an attacker.
Rule | Severity | Likelihood |
|---|
Detectable | Repairable | Priority | Level |
|---|---|---|---|
STR38-C | High |
Likely |
Yes |
No |
P18 | L1 |
Automated Detection
Modern compilers recognize the difference between a char * and a wchar_t * pointer. As a result, so compiling code that violates this rule will generate warnings. It is feasible to have automated software that recognizes improper-width functions and of improper width and replaces them with their functions of proper width functions, i.e. using wcsncpy (that is, software that uses wcsncpy() when it recognizes that the parameters are of type wchar_t *).
Tool | Version | Checker | Description | ||||||
| Astrée |
| wide-narrow-string-cast wide-narrow-string-cast-implicit | Partially checked | ||||||
| Axivion Bauhaus Suite |
| CertC-STR38 | Fully implemented | ||||||
| Clang |
| -Wincompatible-pointer-types | |||||||
| CodeSonar |
| LANG.MEM.BO | Buffer Overrun | ||||||
| Coverity |
| PW | Implemented | ||||||
| Cppcheck Premium |
| premium-cert-str38-c | |||||||
| Helix QAC |
| C0432 C++0403 | |||||||
| Klocwork |
| CXX.DIFF.WIDTH.STR_AND_FUNC | |||||||
| Parasoft C/C++test |
| CERT_C-STR38-a | Do not confuse narrow and wide character strings and functions | ||||||
| PC-lint Plus |
| 2454, 2480, 2481 | Partially supported: reports illegal conversions involving pointers to char or wchar_t as well as byte/wide-oriented stream inconsistencies | ||||||
| Polyspace Bug Finder |
| Checks for misuse of narrow or wide character string (rule fully covered) | |||||||
| RuleChecker |
| wide-narrow-string-cast wide-narrow-string-cast-implicit | Partially checked | ||||||
| Security Reviewer - Static Reviewer |
| UNSAFE_02 | Fully implemented | ||||||
| TrustInSoft Analyzer |
| pointer arithmetic | Partially verified. |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
...
Bibliography
...
...
...
| 2024] | 7.26.2. |
...
| 5, |
...
| "The |
...
strncpy Function"7.31.4.2.2, |
...
"The wcsncpy Function" |
...