【缺陷周话】第22期:错误的内存释放对象
字数 1936 2025-08-18 11:37:57
错误的内存释放对象缺陷分析与防护指南
1. 缺陷概述
错误的内存释放对象(CWE-590: Free of Memory not on the Heap)是指程序尝试释放非动态分配的内存,导致内存数据结构损坏的安全缺陷。这种缺陷可能导致程序崩溃、拒绝服务攻击,在某些情况下甚至可能被利用来修改关键程序变量或执行恶意代码。
2. C/C++内存分配方式
C/C++程序内存分配主要有三种方式:
-
静态存储区域分配
- 存放全局变量和static变量
- 内存在程序编译时分配
- 程序运行期间不会被回收
-
栈上分配
- 由编译器自动分配
- 存放函数参数值和局部变量
- 函数执行结束时自动释放
- 注意:
alloca()函数是向栈申请内存的
-
堆上分配(动态分配)
- 由程序员手动分配和释放
- 使用
malloc/calloc/realloc分配,free释放 - 或使用
new/new[]分配,delete/delete[]释放
关键点:只有第三种堆上分配的内存需要程序员手动释放,对前两种内存进行手动释放会导致错误的内存释放对象问题。
3. 缺陷危害
错误的内存释放对象可能导致:
- 程序内存数据结构损坏
- 程序崩溃
- 拒绝服务攻击(DoS)
- 可能被利用修改关键程序变量
- 可能被利用执行恶意代码
CVE案例(2018-2019):
- CVE-2018-7554:sam2p中的
ReadImage函数无效释放导致DoS - CVE-2018-7552:sam2p中的
Mapping::DoubleHash::clear函数无效释放导致DoS - CVE-2018-7551:sam2p中的
MiniPS::delete0函数无效释放导致DoS - CVE-2018-15857:xkbcommon中的
ExprAppendMultiKeysymList函数无效释放导致解析器崩溃
4. 缺陷代码示例
// 缺陷代码示例
void bad()
{
char * data;
data = (char *)alloca(100*sizeof(char)); // 栈上分配内存
// ... 使用data的代码 ...
delete [] data; // 错误:尝试释放栈内存
}
问题分析:
- 第2行使用
alloca()函数在栈上申请内存 - 第5行错误地使用
delete[]尝试释放栈内存 - 这会导致"错误的内存释放对象"问题
5. 修复方案
5.1 正确修复代码
// 修复后的代码
void good()
{
char * data;
data = new char[100]; // 堆上动态分配内存
// ... 使用data的代码 ...
delete [] data; // 正确:释放动态分配的内存
}
修复要点:
- 使用
new[]在堆上动态分配内存 - 使用
delete[]正确释放动态分配的内存 - 确保分配和释放方式匹配(
new对应delete,new[]对应delete[])
5.2 其他修复建议
-
对于栈内存(如局部变量、
alloca分配的内存):- 不要手动释放
- 让编译器自动管理其生命周期
-
对于静态存储区域内存(如全局变量、static变量):
- 不要手动释放
- 其生命周期与程序相同
-
对于动态分配的内存:
- 确保分配和释放配对使用
- 使用
malloc/calloc/realloc分配的内存使用free释放 - 使用
new分配的内存使用delete释放 - 使用
new[]分配的内存使用delete[]释放
6. 防护最佳实践
-
明确内存来源:
- 在释放内存前,确认内存是通过动态分配方式获得的
- 对于复杂程序结构(如多条件分支),确保释放路径正确
-
了解特殊函数行为:
alloca():在栈上分配内存,不要手动释放realloc():只能用于重新分配由malloc/calloc/realloc分配的内存- 错误示例:
realloc()的第一个参数指向非动态分配的内存
- 错误示例:
-
代码审查要点:
- 检查所有
free/delete/delete[]操作 - 确认被释放的内存确实来自动态分配
- 特别注意条件分支中的内存释放操作
- 检查所有
-
使用静态分析工具:
- 使用如360代码卫士等工具进行自动化检测
- 配置工具规则检测潜在的错误内存释放
-
编码规范建议:
- 统一内存管理策略(如使用RAII、智能指针)
- 避免混合使用不同内存分配/释放方式
- 对动态分配的内存添加明确的注释说明
7. 相关CWE条目
- CWE-590: Free of Memory not on the Heap
- 相关缺陷:
- CWE-415: Double Free(双重释放)
- CWE-416: Use After Free(释放后使用)
- CWE-762: Mismatched Memory Management Routines(内存管理例程不匹配)
8. 总结
错误的内存释放对象是C/C++程序中常见的内存管理错误,可能导致严重的安全问题。开发人员应当:
- 清楚区分不同类型的内存分配方式
- 只释放动态分配的内存
- 确保分配和释放方式正确匹配
- 使用工具辅助检测潜在问题
- 遵循良好的内存管理实践
通过遵循这些原则,可以有效避免错误的内存释放对象缺陷,提高程序的稳定性和安全性。