Errors can occur when assumptions are made about the type of data being read. These assumptions may be violated, for example, when binary data has been read from a file instead of text from a user's terminal. (See recommendation FIO14-C. Understand the difference between text mode and binary mode with file streams.) On some systems, it may also be possible to input a null byte (as well as other binary codes) from the keyboard.
C99, Section 7.19.7.2, "The fgets function", paragraph 3 says
The
fgetsfunction returnssif successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned.
Therefore, if fgets() returns a non-null pointer, we can assume it actually filled the array with data. However, assuming that it filled the array with a non-empty null-terminated byte string (NTBS) is erroneous because the data it placed in the array may contain null characters.
This noncompliant code example attempts to remove the trailing new-line (\n) from an input line. The fgets() function is typically used to read a new-line terminated-line of input from a stream. It takes a size parameter for the destination buffer and copies, at most, size-1 characters from a stream to a character array.
char buf[BUFSIZ + 1];
if (fgets(buf, sizeof(buf), stdin) == NULL) {
/* Handle error */
}
buf[strlen(buf) - 1] = '\0';
|
The strlen() function computes the length of a string by determining the number of characters that precede the terminating null character. A problem occurs if the first character read from the input by fgets() happens to be a null character. This may occur, for example, if a binary data file is read by the fgets() call [Lai 2006]. If the first character in buf is a null character, strlen(buf) returns 0 and a write-outside-array-bounds error occurs.
This compliant solution uses strchr() to replace the new-line character in the string, if it exists. (See rue FIO36-C. Do not assume a new-line character is read when using fgets().)
char buf[BUFSIZ + 1];
char *p;
if (fgets(buf, sizeof(buf), stdin)) {
p = strchr(buf, '\n');
if (p) {
*p = '\0';
}
}
else {
/* Handle error condition */
}
|
Assuming character data has been read can result in an out-of-bounds memory write.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
|---|---|---|---|---|---|
FIO37-C |
high |
probable |
medium |
P12 |
L1 |
Tool |
Version |
Checker |
Description |
||
|---|---|---|---|---|---|
|
|
|
|
||
|
|
|
|
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
CERT C++ Secure Coding Standard: FIO37-CPP. Do not assume character data has been read
ISO/IEC 9899:1999 Section 7.19.7.2, "The fgets function"
MITRE CWE: CWE-119, "Failure to Constrain Operations within the Bounds of an Allocated Memory Buffer"
MITRE CWE: CWE-241, "Failure to Handle Wrong Data Type"
[Lai 2006]
[Seacord 2005a] Chapter 2, "Strings"
FIO36-C. Do not assume a new-line character is read when using fgets() 09. Input Output (FIO) FIO38-C. Do not use a copy of a FILE object for input and output