CWE-464 is the mirror of its neighbor CWE-463. Instead of a sentinel being deleted, one is accidentally added. Data structure sentinels, like the null character ending a C string or an end marker in a linked list, mark where data stops. If one appears in the middle, the data is cut short.
It affects C and C++ code that handles user input in buffers.
How it happens
MITRE's example fills a character array, with the third character taken from user input:
char *foo;
foo = malloc(sizeof(char) * 5);
foo[0] = 'a';
foo[1] = 'a';
foo[2] = fgetc(stdin);
foo[3] = 'c';
foo[4] = '\0';
printf("%c %c %c %c %c \n", foo[0], foo[1], foo[2], foo[3], foo[4]);
printf("%s\n", foo);
If a NULL byte is read from stdin, fgetc returns 0. Printed as a string, the 0 at foo[2] acts as a terminator, and the second printf never reaches foo[3]. The data is truncated.
Another path from MITRE: a parsing function that fails may return a value equal to the sentinel, which then gets stored as if it were data.
What an attacker gains
MITRE lists an integrity impact. The structure generally stops working properly, truncating the data. If the truncated string was a path, a name or a command, that changes what the program does with it.
How to find it
The record lists no detection methods. Search for places where untrusted bytes are placed into strings or lists whose structure depends on a sentinel. Test with NULL bytes and other control values.
How to fix it
From the record:
- Encapsulate the user from interacting with data sentinels, and validate input to verify that sentinels are not present.
- Do proper error checking. If a parsing function fails, it might return a value equal to the sentinel.
- Use an abstraction library to abstract away risky APIs. Not a complete solution.
- Use OS-level preventative functionality. Not a complete solution.
A simple guard for the example:
int c = fgetc(stdin);
if (c == EOF || c == '\0') {
/* reject input */
}
foo[2] = (char)c;
Quick check
What happened to the fourth character in the example?
A NULL byte at position two ended the string early, so printf stopped before it.