CWE-170: Improper Null Termination

Description

The product does not terminate or incorrectly terminates a string or array with a null character or equivalent terminator.

Submission Date :

July 19, 2006, midnight

Modification Date :

2023-06-29 00:00:00+00:00

Organization :

MITRE
Extended Description

Null termination errors frequently occur in two different ways. An off-by-one error could cause a null to be written out of bounds, leading to an overflow. Or, a program could use a strncpy() function call incorrectly, which prevents a null terminator from being added at all. Other scenarios are possible.

Example Vulnerable Codes

Example - 1

The following code reads from cfgfile and copies the input into inputbuf using strcpy(). The code mistakenly assumes that inputbuf will always contain a NULL terminator.


#define MAXLEN 1024...char *pathbuf[MAXLEN];...read(cfgfile,inputbuf,MAXLEN); //does not null terminatestrcpy(pathbuf,inputbuf); //requires null terminated input...

The code above will behave correctly if the data read from cfgfile is null terminated on disk as expected. But if an attacker is able to modify this input so that it does not contain the expected NULL character, the call to strcpy() will continue copying from memory until it encounters an arbitrary NULL character. This will likely overflow the destination buffer and, if the attacker can control the contents of memory immediately following inputbuf, can leave the application susceptible to a buffer overflow attack.

Example - 2

In the following code, readlink() expands the name of a symbolic link stored in pathname and puts the absolute path into buf. The length of the resulting value is then calculated using strlen().


char buf[MAXPATH];...readlink(pathname, buf, MAXPATH);int length = strlen(buf);...

The code above will not always behave correctly as readlink() does not append a NULL byte to buf. Readlink() will stop copying characters once the maximum size of buf has been reached to avoid overflowing the buffer, this will leave the value buf not NULL terminated. In this situation, strlen() will continue traversing memory until it encounters an arbitrary NULL character further on down the stack, resulting in a length value that is much larger than the size of string. Readlink() does return the number of bytes copied, but when this return value is the same as stated buf size (in this case MAXPATH), it is impossible to know whether the pathname is precisely that many bytes long, or whether readlink() has truncated the name to avoid overrunning the buffer. In testing, vulnerabilities like this one might not be caught because the unused contents of buf and the memory immediately following it may be NULL, thereby causing strlen() to appear as if it is behaving correctly.

Example - 3

While the following example is not exploitable, it provides a good example of how nulls can be omitted or misplaced, even when "safe" functions are used:



char longString[] = "String signifying nothing";char shortString[16];strncpy(shortString, longString, 16);printf("The last character in shortString is: %c (%1$x)\n", shortString[15]);return (0);#include <stdio.h>#include <string.h>int main() {}

The above code gives the following output: "The last character in shortString is: n (6e)". So, the shortString array does not end in a NULL character, even though the "safe" string function strncpy() was used. The reason is that strncpy() does not impliciitly add a NULL character at the end of the string when the source is equal in length or longer than the provided size.

Visit http://cwe.mitre.org/ for more details.