MEM50-CPP. 不要访问被释放的内存
- 1. 不合规的代码示例 (new and delete)
- 2. 合规方案 (new and delete)
- 3. 合规方案 (Automatic Storage Duration)
- 4. 不合规的代码示例 (std::unique_ptr)
- 5. 合规方案 (std::unique_ptr)
- 6. 合规方案
- 7. 不合规的代码示例 (std::string::c_str())
- 8. 合规方案 (std::string::c_str())
- 9. 不合规的代码示例
- 10. 合规方案
- 11. 合规方案
- 12. Risk Assessment
- 13. Automated Detection
- 14. Related Vulnerabilities
- 15. Related Guidelines
- 16. Bibliography
原文链接:
MEM50-CPP. Do not access freed memory
使用已经被指向被内存管理函数释放的指针——包括解引用、作为运算的操作数、类型转换和作为赋值的右值——是 未定义行为 。指向已经被释放的内存的指针被称为 空悬指针 。访问一个空悬指针会导致可用 漏洞(exploitable vulnerabilities)。
何时去重用或者回收被释放的内存却决于内存管理单元。当内存被释放了,所有的指针将成为不合法的,并且它的上下文可能被返回给操作系统、使被释放内存不可访问或者依然完好无损且可访问。结果就是,处于被释放内存区域的数据可能看起来合法但可能已经意外改变了。因此,当内存被释一旦被释放,一定不要从它当中读或写。
不合规的代码示例 (new
and delete
)
这个不合规的代码示例中,已经被释放的 s
被解引用了。如果这次访问导致读后释放(write-after-free),这个 漏洞(vulnerability) 可被 发掘 来用于执行任意带权限的漏洞进程代码。通常,动态内存分配和释放相距甚远,使得这类问题很难被识别和分析。
1 |
|
函数 g()
被标记为 noexcept(false)
以遵循 MEM52-CPP. Detect and handle memory allocation errors.
合规方案 (new
and delete
)
在这个合规方案中, 动态分配的内存直到不被使用后才释放。
1 |
|
合规方案 (Automatic Storage Duration)
当有可能时,使用自动存储期 (Automatic Storage Duration) 来代替动态存储期 (dynamic storage duration) 。既然 s
在 g()
范围之外不再被用到,这个合规方案利用自动存储期来限制在 g()
作用范围内的 s
的生命周期。
1 | struct S { |
不合规的代码示例 (std::unique_ptr
)
在接下来这个不合规的代码示例中, buff
对象的析构函数在隐式地释放了由 buff
对象管理的动态分配的内存之后,这块内存被访问了。
1 |
|
这段代码总是构造了一个 null 结尾的字符串,即使用了 strncpy()
,因为它把缓冲区的末尾 char
设为 0。
合规方案 (std::unique_ptr
)
在这个合规方案中, buff
的生命周期被延长到了访问被其管理的内存之后。
1 |
|
合规方案
在这个合规方案中,使用了一个带由自动存储期的 std::string
类型的变量来代替 std::unique_ptr<char[]>
,这降低了方案的复杂度且提高了安全性。
1 |
|
不合规的代码示例 (std::string::c_str()
)
在这个不合规的代码示例中,在一个临时的 std::string
对象上调用了 std::string::c_str()
。一旦 std::string
对象在赋值运算结束后被销毁,存放结果的指针将指向被释放的内存。当访问了指针指向的元素时,将导致 未定义行为 。
1 |
|
这段代码总是构造了一个 null 结尾的字符串,即使用了 strncpy()
,因为它把缓冲区的末尾 char
设为 0。
合规方案 (std::string::c_str()
)
在这个合规方案中,构造了该字符串的局部拷贝来确保当调用 display_string()
时,字符串 str
将是可用的。
1 |
|
不合规的代码示例
在这个不合规的代码示例中,试图通过调用 operator new()
来分配零字节的内存。如果该请求成功, operator new()
应返回非空指针值。然而,根据 C++ 标准,[basic.stc.dynamic.allocation], 段落 2 [ISO/IEC 14882-2014], 试图通过这类指针来解引用将导致 未定义行为 。
1 |
|
合规方案
在这个合规方案依赖程序员的意图。如果程序员试图分配单个 unsigned char
对象,这个合规方案将利用 new
来替代直接调用 operator new()
,如该合规方案所示。
1 | void f() noexcept(false) { |
合规方案
如果程序员试图分配零字节的内存(大概想得到一个不会被程序中其他指针复用的独有的指针值,除非它被正确释放),然后并不是试图去解引用这个返回的指针,建议的方案而是将 ptr
声明为 void *
类型。根据 一致性 (conforming) 实现 (implementation)., 它不能被解引用。
1 | void f() noexcept(false) { |
Risk Assessment
读取已经被释放的先前动态分配过的内存将导致 程序异常终止 abnormal program termination 和 拒绝服务攻击 denial-of-service attacks. 对已经被释放的内存写入会导致执行提权的任意代码漏洞程序。
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MEM50-CPP | High | Likely | Medium | P18 | L1 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
Astrée | 20.10 | dangling_pointer_use | |
Axivion Bauhaus Suite | 7.2.0 | CertC++-MEM50 | |
Clang | 3.9 | clang-analyzer-cplusplus.NewDeleteclang-analyzer-alpha.security.ArrayBoundV2 |
Checked by clang-tidy , but does not catch all violations of this rule. |
CodeSonar | 6.1p0 | ALLOC.UAF | Use after free |
Compass/ROSE | |||
Coverity | v7.5.0 | USE_AFTER_FREE | Can detect the specific instances where memory is deallocated more than once or read/written to the target of a freed pointer |
Helix QAC | 2021.2 | C++4303, C++4304 | |
Klocwork | 2021.1 | UFM.DEREF.MIGHT UFM.DEREF.MUST UFM.FFM.MIGHT UFM.FFM.MUST UFM.RETURN.MIGHT UFM.RETURN.MUST UFM.USE.MIGHT UFM.USE.MUST | |
LDRA tool suite | 9.7.1 | 483 S, 484 S** ** | Partially implemented |
Parasoft C/C++test | 2021.1 | **CERT_CPP-MEM50-a ** | Do not use resources that have been freed |
Parasoft Insure++ | Runtime detection | ||
Polyspace Bug Finder | R2021b | CERT C++: MEM50-CPP | Checks for:Pointer access out of boundsDeallocation of previously deallocated pointerUse of previously freed pointerRule partially covered. |
PRQA QA-C++ | 4.4 | 4303, 4304 | |
PVS-Studio | 7.15 | V586, V774 | |
Splint | 5.0 |
Related Vulnerabilities
VU#623332 describes a double-free vulnerability in the MIT Kerberos 5 function krb5_recvauth() [VU# 623332].
Search for other vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
Bibliography
[ISO/IEC 14882-2014] | Subclause 3.7.4.1, “Allocation Functions” Subclause 3.7.4.2, “Deallocation Functions” |
---|---|
[Seacord 2013b] | Chapter 4, “Dynamic Memory Management” |
本文标题:MEM50-CPP. 不要访问被释放的内存
文章作者:xwnb
发布时间:2021-11-10
最后更新:2023-04-17
原始链接:https://xwnb.github.io/posts/1419131790/
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!并保留本声明。感谢您的阅读和支持!
分享