...
Because the input is unbounded, the following code could lead to a buffer overflow:.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <iostream> void f() { char buf[12]; std::cin >> buf; } |
...
To solve this problem, it may be tempting to use the std::ios_base::width()
method, but there still is a trap, as shown in this noncompliant code example:.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <iostream> void f() { char bufOne[12]; char bufTwo[12]; std::cin.width(12); std::cin >> bufOne; std::cin >> bufTwo; } |
In this example, the first read will not overflow, but could fill bufOne
with a truncated string. Furthermore the Furthermore, the second read still could overflow bufTwo
. The C++ Standard, [istream.extractors], paragraphs 7–9 [ISO/IEC 14882-2014], describes the behavior of operator>>(basic_istream &, charT *)
and, and states in part [ISO/IEC 14882-2014]in part, states the following:
operator>>
then stores a null byte (charT()
) in the next position, which may be the first position if no characters were extracted.operator>>
then callswidth(0)
.
...
The best solution for ensuring that data is not truncated and for guarding against buffer overflows is to use std::string
instead of a bounded array, as in this compliant solution:.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <iostream> #include <string> void f() { std::string input; std::string stringOne, stringTwo; std::cin >> stringOne >> stringTwo; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <fstream> #include <string> void f(std::istream &in) { char buffer[32]; try { in.read(buffer, 32sizeof(buffer)); } catch (std::ios_base::failure &e) { // Handle error } std::string str(buffer); // ... } |
Compliant Solution
This compliant solution continues to assume assumes that the input from the file is exactly at most 32 characters, and instead . Instead of inserting a null terminator, it constructs the std::string
object based on the sizenumber of characters read from the input stream. If the size of the input is uncertain, it is better to use std::basic_istream<T>::readsome()
or a formatted input function, depending on need.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <fstream> #include <string> void f(std::istream &in) { char buffer[32]; try { in.read(buffer, 32sizeof(buffer)); } catch (std::ios_base::failure &e) { // Handle error } std::string str(buffer, 32in.gcount()); // ... } |
Risk Assessment
Copying string data to a buffer that is too small to hold that data results in a buffer overflow. Attackers can exploit this condition to execute arbitrary code with the permissions of the vulnerable process.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
STR50-CPP | High | Likely | Medium | P18 | L1 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| stream-input-char-array | Partially checked + soundly supported | ||||||
CodeSonar |
| MISC.MEM.NTERM LANG.MEM.BO | No space for null terminator Buffer overrun | ||||||
Helix QAC |
| C++5216 DF2835, DF2836, DF2839, | |||||||
Klocwork |
| NNTS.MIGHT NNTS.TAINTED NNTS.MUST SV.UNBOUND_STRING_INPUT.CIN | |||||||
LDRA tool suite |
| 489 S, 66 X, 70 X, 71 X | Partially implemented | ||||||
Parasoft C/C++test |
| CERT_CPP-STR50-b | Avoid overflow due to reading a not zero terminated string | |||||||
Polyspace Bug Finder |
| CERT C++: STR50-CPP | Checks for:
Rule partially covered. | ||||||
RuleChecker |
| stream-input-char-array | Partially checked | ||||||
SonarQube C/C++ Plugin |
| S3519 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
SEI CERT C Coding Standard | STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator |
Bibliography
[ISO/IEC 14882-2014] | Subclause 27.7.2.2.3, " |
[Seacord 2013] | Chapter 2, "Strings" |
...
...