You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 89 Next »

Errors can occur when incorrect 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 or the output of a process is piped to stdin. (See 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.

Subclause 7.21.7.2 of the C Standard [ISO/IEC 9899:2011] says,

The fgets function returns s if 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.

The wide-character function fgetws() has the same behavior. Therefore, if fgets() or fgetws() returns a non-null pointer, it is safe to assume that the array contains data. However, it is erroneous to assume that the array contains a nonempty string because the data may contain null characters.

Noncompliant Code Example

This noncompliant code example attempts to remove the trailing newline (\n) from an input line. The fgets() function is typically used to read a newline-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.

#include <stdio.h>
#include <string.h>
 
enum { BUFFER_SIZE = 1024 };

void func(void) {
  char buf[BUFFER_SIZE];

  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, the expression strlen(buf) - 1 wraps around to a large positive value, and a write-outside-array-bounds error occurs.

Compliant Solution

This compliant solution uses strchr() to replace the newline character in the string if it exists:

#include <stdio.h>
#include <string.h>
 
enum { BUFFER_SIZE = 1024 };

void func(void) {
  char buf[BUFFER_SIZE];
  char *p;

  if (fgets(buf, sizeof(buf), stdin)) {
    p = strchr(buf, '\n');
    if (p) {
      *p = '\0';
    }
  } else {
    /* Handle error */
  }
}

Risk Assessment

Incorrectly assuming that character data has been read can result in an out-of-bounds memory write or other flawed logic.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

FIO37-C

High

Probable

Medium

P12

L1

Automated Detection

Tool

Version

Checker

Description

Astrée24.04 Supported, but no explicit checker
CodeSonar8.1p0(general)Considers the possibility that fgets() and fgetws() may return empty strings (Warnings of various classes may be triggered depending on subsequent operations on those strings. For example, the noncompliant code example cited above would trigger a buffer underrun warning.)
Compass/ROSE

 

 

Could detect some violations of this rule (In particular, it could detect the noncompliant code example by searching for fgets(), followed by strlen() - 1, which could be −1. The crux of this rule is that a string returned by fgets() could still be empty, because the first char is '\0'. There are probably other code examples that violate this guideline; they would need to be enumerated before ROSE could detect them.)

LDRA tool suite9.7.144 SEnhanced enforcement
Parasoft C/C++test9.5BD-PB-ARRAYFully implemented
PRQA QA-C++4.2 2840, 2841, 2842, 2843, 2844 

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

CERT C Secure Coding Standard FIO14-C. Understand the difference between text mode and binary mode with file streams
FIO20-C. Avoid unintentional truncation when using fgets() or fgetws()
MITRE CWECWE-119, Improper Restriction of Operations within the Bounds of a Memory Buffer
CWE-123, Write-what-where Condition
CWE-125, Out-of-bounds Read
CWE-241, Improper Handling of Unexpected Data Type

Bibliography

[ISO/IEC 9899:2011]

Subclause 7.21.7.2, "The fgets Function"
Subclause 7.29.3.2, "The fgetws Function"

[Lai 2006] 
[Seacord 2013]Chapter 2, "Strings"

 


  • No labels