
The fgets()
function is typically used to read a newline-terminated line of input from a stream. The fgets()
function takes a size parameter for the destination buffer and copies, at most, size - 1
characters from a stream to a string. Truncation errors can occur if the buffer size is smaller than the input string.
The fgetws()
function is similarly affected.
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 instance, since the buffer is only 8 characters in length, if the user input "Hello World\n", the buffer would contain "Hello W" and the null terminator.
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 it is not at the end-of-file and not a newline, then the user's input has been cut short.
#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" |