原文链接:

CTR52-CPP. Guarantee that library functions do not overflow

https://wiki.sei.cmu.edu/confluence/display/cplusplus/CTR52-CPP.+Guarantee+that+library+functions+do+not+overflow

拷贝数据到一个不够容纳这些数据的容器中导致缓冲区溢出。为了避免这类错误,被拷贝到目标容器的数据必须严格限制在目标容器的尺寸下,或者更完美的,目标容器必须确保足够大来容纳将被拷贝的数据。

Copying data into 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 container must be restricted on the basis of the destination container’s size, or preferably, the destination container must be guaranteed to be large enough to hold the data to be copied.

由拷贝数据到尺寸不足的缓冲区导致的 漏洞 也会涉及 null 结尾的字符串。参阅 STR50-CPP. Guarantee that storage for strings has sufficient space for character data and the null terminator 获取涉及字符串的例子。

Vulnerabilities that result from copying data to an undersized buffer can also involve null-terminated strings. Consult STR50-CPP. Guarantee that storage for strings has sufficient space for character data and the null terminator for specific examples of this rule that involve strings.

拷贝可以使用 std::memcpy() 函数。然而, std::memmove()std::memset() 函数也会导致相同的漏洞,因为在覆写一块内存时没有检查该块是否有效。这类问题不止现定于 C 标准库函数;标准模板库 (STL) 泛型算法,例如 std::copy()std::fill(),和 std::transform() 也假定有效的输出缓冲区尺寸 [ISO/IEC 14882-2014].。

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 容器也会遭受与数组数据类型相同的漏洞。std::copy() 算法没有提供内部边界检查,会导致缓冲区溢出。在这个不合规的示例代码中,使用 std::copy(),把一个整型的 vector 从 src 拷贝到 dest 中。因为 std::copy() 不会展开 dest vector,程序在拷贝第一个元素时将溢出缓冲区。

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 a buffer overflow. In this noncompliant code example, a vector of integers is copied from src to dest using std::copy(). Because std::copy() does nothing to expand the dest vector, the program will overflow the buffer on copying the first element.

1
2
3
4
5
6
7
8
#include <algorithm>
#include <vector>

void f(const std::vector<int> &src) {
std::vector<int> dest;
std::copy(src.begin(), src.end(), dest.begin());
// ...
}

这个风险在适用任何期望将值填入目标迭代器的算法。大多数 STL 算法期望目标容器有足够的空间来容纳提供的值。

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.

合规方案 (Sufficient Initial Capacity) Compliant Solution (Sufficient Initial Capacity)

使用 std::copy() 恰当的方式是确保目标容器可以容纳所有正被拷贝进去的元素。这个合规方案扩容 vector 容量优先拷贝操作。

The 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.

1
2
3
4
5
6
7
8
#include <algorithm>
#include <vector>
void f(const std::vector<int> &src) {
// Initialize dest with src.size() default-inserted elements
std::vector<int> dest(src.size());
std::copy(src.begin(), src.end(), dest.begin());
// ...
}

合规方案 (Per-Element Growth) Compliant Solution (Per-Element Growth)

可选的方法是提供一个 std::back_insert_iterator 作为目标容器的实参。这个迭代器会对每个算法提供的元素扩展目标容器,这保证了目标容器将变得足够大来容纳被提供的元素。

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 provided.

1
2
3
4
5
6
7
8
9
#include <algorithm>
#include <iterator>
#include <vector>

void f(const std::vector<int> &src) {
std::vector<int> dest;
std::copy(src.begin(), src.end(), std::back_inserter(dest));
// ...
}

合规的方案 (Assignment) Compliant Solution (Assignment)

最简单的方法就是直接用 src 来构造 dest,像这个合规方案里展示的。

The simplest solution is to construct dest from src directly, as in this compliant solution.

1
2
3
4
5
6
#include <vector>

void f(const std::vector<int> &src) {
std::vector<int> dest(src);
// ...
}

不合规代码示例 Noncompliant Code Example

在这个不合规的代码示例中, std::fill_n() 被用来填充 10 个值为 0x42 到缓冲区中。然而,缓冲区没有为这些数据分配任何空间,所以该操作导致缓冲区溢出。

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.

1
2
3
4
5
6
7
#include <algorithm>
#include <vector>

void f() {
std::vector<int> v;
std::fill_n(v.begin(), 10, 0x42);
}

合规的方案 (Sufficient Initial Capacity) Compliant Solution (Sufficient Initial Capacity)

这个合规的方案保证在试图填充容器之前容器的容量是足够的。

This compliant solution ensures the capacity of the vector is sufficient before attempting to fill the container.

1
2
3
4
5
6
7
#include <algorithm>
#include <vector>

void f() {
std::vector<int> v(10);
std::fill_n(v.begin(), 10, 0x42);
}

然而,这个合规方案是不充分的。构造器将默认构造 10 个类型为 int 的元素,在调用 std::fill_n() 时,这些元素立马被替换,这意味着容器内的每个元素被初始化的两次。

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.

合规的方案 (Fill Initialization) Compliant Solution (Fill Initialization)

这个合规方案中初始化 v 为 10 个值都为 0x42 的元素。

This compliant solution initializes v to 10 elements whose values are all 0x42.

1
2
3
4
5
6
#include <algorithm>
#include <vector>

void f() {
std::vector<int> v(10, 0x42);
}

风险评估 Risk Assessment

拷贝数据到不足以容纳数据大小的缓冲区中导致缓冲区溢出。攻击者可以 利用 这个状况来执行任意代码。

Copying data to a buffer that is too small to hold 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 Version Checker Description
CodeSonar img **BADFUNC.BO.*****LANG.MEM.BO** A collection of warning classes that report uses of library functions prone to internal buffer overflows.Buffer Overrun
Parasoft C/C++test img CERT_CPP-CTR52-a Do not pass empty container iterators to std algorithms as destinations

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

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”

SEI CERT C++ Coding Standard > SEI CERT C++ Coding Standard > button_arrow_left.png SEI CERT C++ Coding Standard > SEI CERT C++ Coding Standard > button_arrow_up.png SEI CERT C++ Coding Standard > SEI CERT C++ Coding Standard > button_arrow_right.png