The fgets()
and fgetws()
functions are typically used to read a newline-terminated line of input from a stream. Both functions read at most one less than the number of narrow or wide characters specified by an argument n
from a stream to a string. Truncation errors can occur if n - 1
is less than the number of characters appearing in the input string prior to the new-line narrow or wide character (which is retained) or after end-of-file. This can result in the accidental truncation of user input.
Noncompliant Code Example
This noncompliant code example copies the input string into a buffer, and assumes it captured all of the user's input.
#include <stdbool.h> #include <stdio.h> bool get_data(char *buffer, int size) { if (fgets(buffer, size, stdin)) { return true; } return false; } void func(void) { char buf[8]; if (get_data(buf, sizeof(buf))) { printf("The user input %s\n", buf); } else { printf("Error getting data from the user\n"); } }
However, if the last character in buf
is not a newline and the stream is not at the end-of-file marker, the buffer was too small to contain all of the data from the user. For example, because the buffer is only 8 characters in length, if the user input "Hello World\n"
, the buffer would contain "Hello W"
terminated by a null character.
Compliant Solution
This compliant solution examines the end-of-file marker for the stream and the last character in the buffer to determine whether it is a newline or not. If it is the end of file, or the last character is a newline, then the buffer contains all of the user's input. However, if the last character is not at the end-of-file and not a newline then the user's input has been truncated.
#include <stdbool.h> #include <stdio.h> #include <string.h> bool get_data(char *buffer, int size) { if (fgets(buffer, size, stdin)) { size_t len = strlen(buffer); return feof(stdin) || buffer[len] == '\n'; } return false; } void func(void) { char buf[8]; if (get_data(buf, sizeof(buf))) { printf("The user input %s\n", buf); } else { printf("Error getting data from the user\n"); } }
Risk Assessment
Incorrectly assuming a newline character is read by fgets()
or fgetws()
can result in data truncation.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
FIO36-C | medium | likely | medium | P12 | L1 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
CERT C++ Secure Coding Standard | FIO36-CPP. Do not assume a new-line character is read when using fgets() |
Bibliography
[Lai 2006] | |
[Seacord 2013] | Chapter 2, "Strings" |