Copying data into an array a container that is not large enough to hold that data results in a buffer overflow. To prevent such errors, data copied to the destination array container must be restricted based on the size basis of the destination arraycontainer's size, or , preferably, the destination array container must be guaranteed to be large enough to hold the data to be copied.
Vulnerabilities that result from copying data to an undersized buffer often can also involve null-terminated byte strings (NTBS). Consult STR31STR50-CPP. Guarantee that storage for character arrays strings has sufficient space for character data and the null terminator for for specific examples of this rule that involve NTBS.
Noncompliant Code Example
strings.
Copies can be made with the std::memcpy()
function. However, the std::memmove()
and std::memset()
functions can also have the same vulnerabilities because they overwrite a block of memory without checking that the block is valid. Such issues are not limited to C standard library functions; standard template library (STL) generic algorithms, such as std::copy()
, std::fill()
, and std::transform()
, also assume valid output buffer sizes [ISO/IEC 14882-2014].
Noncompliant Code Example
STL containers can be subject to the same vulnerabilities as array data types. The std::copy()
algorithm provides no inherent bounds checking and can lead to Improper use of functions that limit copies with a size specifier, such as memcpy()
, may result in a buffer overflow. In this noncompliant code example, an array a vector of integers is copied from src
to dest
using memcpystd::copy()
. However, the programmer mistakenly specified the amount to copy based on the size of src
, which is stored in len,
rather than the space available in dest
. If len
is greater than 256, then a buffer overflow will occur.Because std::copy()
does nothing to expand the dest
vector, the program will overflow the buffer on copying the first element.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <algorithm> enum { WORKSPACE_SIZE = 256 };#include <vector> void funcf(const intstd::vector<int> src[], size_t len&src) { intstd::vector<int> dest[WORKSPACE_SIZE]; memcpy(deststd::copy(src.begin(), src.end(), len * sizeof(intdest.begin()); //* ... */ } |
This hazard applies to any algorithm that takes a destination iterator, expecting to fill it with values. Most of the STL algorithms expect the destination container to have sufficient space to hold the values provided.
Compliant Solution (
...
Sufficient Initial Capacity)
The amount of data copied should be limited based on the available space in the destination buffer. This can be accomplished by adding a check to ensure the amount of data to be copied from src
can fit in dest
proper way to use std::copy()
is to ensure the destination container can hold all the elements being copied to it. This compliant solution enlarges the capacity of the vector prior to the copy operation.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <algorithm> enum { WORKSPACE_SIZE = 256 }; #include <vector> void funcf(const intstd::vector<int> src[], size_t len&src) { // intInitialize dest[WORKSPACE_SIZE]; with if (len > WORKSPACE_SIZE) {src.size() default-inserted elements /* Handle Error */ } memcpy(dest, src, sizeof(int)*lenstd::vector<int> dest(src.size()); std::copy(src.begin(), src.end(), dest.begin()); //* ... */ } |
Compliant Solution (
...
Per-Element Growth)
An alternative approach is to supply a std::back_insert_iterator
as the destination argument. This iterator expands the destination container by one element for each element supplied by the algorithm, which guarantees the destination container will become sufficiently large to hold the elements providedAlternatively, memory for the destination buffer (dest
) can be dynamically allocated to ensure it is large enough to hold the data in the source buffer (src
). Note that this solution checks for numeric overflow (see INT32-CPP. Ensure that operations on signed integers do not result in overflow).
Code Block | ||||
---|---|---|---|---|
| ||||
#include <algorithm> #include <iterator> #include <vector> void funcf(const intstd::vector<int> src[], size_t len&src) { intstd::vector<int> *dest; if (len > SIZE_MAX/sizeof(int)) { /* handle integer overflow */ } dest = (int *)malloc(sizeof(int) * len); if (dest == NULLstd::copy(src.begin(), src.end(), std::back_inserter(dest)); // ... } |
Compliant Solution (Assignment)
The simplest solution is to construct dest
from src
directly, as in this compliant solution.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <vector>
void f(const std::vector<int> &src) {
std::vector<int> dest(src);
// ...
} |
Noncompliant Code Example
In this noncompliant code example, std::fill_n()
is used to fill a buffer with 10 instances of the value 0x42
. However, the buffer has not allocated any space for the elements, so this operation results in a buffer overflow.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <algorithm> #include <vector> void f() { std::vector<int> v; std::fill_n(v.begin(), 10, 0x42); } |
Compliant Solution (Sufficient Initial Capacity)
This compliant solution ensures the capacity of the vector is sufficient before attempting to fill the container.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <algorithm>
#include <vector>
void f() {
std::vector<int> v(10);
std::fill_n(v.begin(), 10, 0x42);
} |
However, this compliant solution is inefficient. The constructor will default-construct 10 elements of type int
, which are subsequently replaced by the call to std::fill_n()
, meaning that each element in the container is initialized twice.
Compliant Solution (Fill Initialization)
This compliant solution initializes v
to 10 elements whose values are all 0x42
.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <algorithm> #include <vector> void f() { std::vector<int> v(10, 0x42); }/* Couldn't get the memory - recover */ } memcpy(dest, src, sizeof(int) * len); /* ... */ free(dest); } |
Risk Assessment
Copying data to a buffer that is too small to hold that the data results in a buffer overflow. Attackers can exploit this condition to execute arbitrary code.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|
CTR52-CPP |
High |
Likely |
Medium | P18 | L1 |
Automated Detection
Tool |
---|
Fortify SCA Version 5.0 can detect violations of this rule.
Splint Version 3.1.1 can detect violations of this rule.
Compass/ROSE can detect some violations of this rule.
...
Version | Checker | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| invalid_pointer_dereference | |||||||
CodeSonar |
| BADFUNC.BO.* | A collection of warning classes that report uses of library functions prone to internal buffer overflows. | ||||||
Helix QAC |
| DF3526, DF3527, DF3528, DF3529, DF3530, DF3531, DF3532, DF3533, DF3534 | |||||||
Parasoft C/C++test |
| CERT_CPP-CTR52-a | Do not pass empty container iterators to std algorithms as destinations | ||||||
Polyspace Bug Finder |
| CERT C++: CTR52-CPP | Checks for library functions overflowing sequence container (rule partially covered). |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the the CERT website.
Other Languages
This rule appears in the C Secure Coding Standard as ARR33-C. Guarantee that copies are made into storage of sufficient size.
References
Wiki Markup |
---|
\[[ISO/IEC 9899:1999|AA. C++ References#ISO/IEC 9899-1999]\] Section 7.21.2, "Copying functions," Section 7.21.2.1, "The memcpy function," and Section 5.1.2.2.1, "Program Startup"
\[[ISO/IEC PDTR 24772|AA. C++ References#ISO/IEC PDTR 24772]\] "XYB Buffer Overflow in Heap," "XYW Buffer Overflow in Stack," and "XYZ Unchecked Array Indexing"
\[[MITRE 07|AA. C++ References#MITRE 07]\] [CWE ID 119|http://cwe.mitre.org/data/definitions/119.html], "Failure to Constrain Operations within the Bounds of an Allocated Memory Buffer"
\[[Seacord 05a|AA. C++ References#Seacord 05]\] Chapter 2, "Strings"
\[[VU#196240|AA. C++ References#VU196240]\] |
Related Guidelines
SEI CERT C++ Coding Standard | STR50-CPP. Guarantee that storage for strings has sufficient space for character data and the null terminator |
SEI CERT C Coding Standard | ARR38-C. Guarantee that library functions do not form invalid pointers |
MITRE CWE | CWE 119, Failure to Constrain Operations within the Bounds of an Allocated Memory Buffer CWE 805, Buffer Access with Incorrect Length Value |
Bibliography
[ISO/IEC 14882-2014] | Subclause 25.3, "Mutating Sequence Operations" |
[ISO/IEC TR 24772-2013] | Buffer Overflow in Heap [XYB] Buffer Overflow in Stack [XYW] Unchecked Array Indexing [XYZ] |
[Meyers 2001] | Item 30, "Make Sure Destination Ranges Are Big Enough" |
...
ARR32-CPP. Ensure size arguments for variable length arrays are in a valid range 06. Arrays (ARR) VOID ARR34-CPP. Ensure that array types in expressions are compatible