Strings must contain a null-termination character at or before the address of the last element of the array before they can be safely passed as arguments to standard string-handling functions, such as strcpy()
or strlen()
. This is because these functions, as well as other string-handling functions defined by C99 by the C standard [ISO/IEC 9899:19992011], depend on the existence of a null-termination character to determine the length of a string. Similarly, strings must be null terminated before iterating on a character array where the termination condition of the loop depends on the existence of a null-termination character within the memory allocated for the string, as in the following example:
Code Block | ||
---|---|---|
| ||
size_t i;
char ntbs[16];
/* ... */
for (i = 0; i < sizeof(ntbs); ++i) {
if (ntbs[i] == '\0') break;
/* ... */
}
|
...
The standard strncpy()
function does not guarantee that the resulting string is null terminated [ISO/IEC 9899:19992011]. If there is no null character is containded in the first n
characters of the source
array, the result could not be null terminated.
In the first noncompliant code example, ntbs
is null-terminated before the call to strncpy()
. However, the subsequent execution of strncpy()
can overwrite the null-termination character.
Code Block | ||||
---|---|---|---|---|
| ||||
char ntbs[NTBS_SIZE];
ntbs[sizeof(ntbs)-1] = '\0';
strncpy(ntbs, source, sizeof(ntbs));
|
...
Code Block | ||||
---|---|---|---|---|
| ||||
char ntbs[NTBS_SIZE];
memset(ntbs, 0, sizeof(ntbs)-1);
strncpy(ntbs, source, sizeof(ntbs)-1);
|
...
Code Block | ||||
---|---|---|---|---|
| ||||
char ntbs[NTBS_SIZE];
strncpy(ntbs, source, sizeof(ntbs)-1);
ntbs[sizeof(ntbs)-1] = '\0';
|
...
Code Block | ||||
---|---|---|---|---|
| ||||
char *source = "0123456789abcdef";
char ntbs[NTBS_SIZE];
/* ... */
if (source) {
if (strlen(source) < sizeof(ntbs)) {
strcpy(ntbs, source);
}
else {
/* handle string too large condition */
}
}
else {
/* handle NULL string condition */
}
|
...
The strncpy_s()
function copies up to n
characters from the source array to a destination array [ISO/IEC TR 24731-1:2007]. If no null character was copied from the source array, then the n
th position in the destination array is set to a null character, guaranteeing that the resulting string is null-terminated.
Code Block | ||||
---|---|---|---|---|
| ||||
char *source;
char a[NTBS_SIZE];
/* ... */
if (source) {
errno_t err = strncpy_s(a, sizeof(a), source, 5);
if (err != 0) {
/* Handle error */
}
}
else {
/* handle NULL string condition */
}
|
...
The following noncompliant code example fails to ensure that cur_msg
is properly null-terminated:
Code Block | ||||
---|---|---|---|---|
| ||||
char *cur_msg = NULL;
size_t cur_msg_size = 1024;
/* ... */
void lessen_memory_usage(void) {
char *temp;
size_t temp_size;
/* ... */
if (cur_msg != NULL) {
temp_size = cur_msg_size/2 + 1;
temp = realloc(cur_msg, temp_size);
if (temp == NULL) {
/* Handle error condition */
}
cur_msg = temp;
cur_msg_size = temp_size;
}
}
/* ... */
|
Because realloc()
does not guarantee that the string is properly null-terminated, any subsequent operation on cur_msg
that assumes a null-termination character may result in undefined behavior.
...
In this compliant solution, the lessen_memory_usage()
function ensures that the resulting string is always properly null-terminated.
Code Block | ||||
---|---|---|---|---|
| ||||
char *cur_msg = NULL;
size_t cur_msg_size = 1024;
/* ... */
void lessen_memory_usage(void) {
char *temp;
size_t temp_size;
/* ... */
if (cur_msg != NULL) {
temp_size = cur_msg_size/2 + 1;
temp = realloc(cur_msg, temp_size);
if (temp == NULL) {
/* Handle error condition */
}
cur_msg = temp;
cur_msg_size = temp_size;
/* ensure string is null-terminated */
cur_msg[cur_msg_size - 1] = '\0';
}
}
/* ... */
|
Risk Assessment
Failure to properly null-terminate strings 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.
...
Tool | Version | Checker | Description | section|||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
| 600 S | Section | Fully Implementedimplemented. | |||||||||
Section | Compass/ROSE |
|
| Section | Can detect some violations of this rule section. | |||||||
| Section | NNTS |
|
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
...
CERT C++ Secure Coding Standard: STR32-CPP. Null-terminate character arrays as required
ISO/IEC 9899:19992011 Section 7.1.1, "Definitions of terms," Section 7.2022.3.4 5, "The realloc
function," and Section 7.2124, "String handling <string.h>
"
ISO/IEC TR 24772 "CJM String Terminationtermination"
ISO/IEC TR 24731-1:2007 Section 6.7.1.4, "The strncpy_s
function"
MITRE CWE: CWE-119, "Failure to Constrain Operations constrain operations within the Bounds bounds of an Allocated Memory Bufferallocated memory buffer"
MITRE CWE: CWE-170, "Improper Null Terminationnull termination"
Bibliography
[Schwarz 2005]
[Seacord 2005a] Chapter 2, "Strings"
[Viega 2005] Section 5.2.14, "Miscalculated NULL
termination"
...