@ohos-graphics/stability-code-review 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +169 -0
- package/SKILL.md +518 -0
- package/bin/install.js +165 -0
- package/config/rules.yaml +445 -0
- package/config/whitelist.yaml +52 -0
- package/package.json +40 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_001.md +275 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_002.md +273 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_003.md +305 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_004.md +350 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_005.md +301 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_006.md +320 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_007.md +432 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_008.md +394 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_009.md +425 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_010.md +472 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_011.md +204 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_012.md +210 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_013.md +226 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_014.md +222 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_015.md +256 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_016.md +269 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_017.md +222 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_018.md +336 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_001.md +414 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_002.md +335 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_003.md +284 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_004.md +313 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_005.md +364 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_001.md +142 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_002.md +222 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_003.md +383 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_001.md +258 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_002.md +131 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_003.md +220 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_004.md +224 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_005.md +250 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_006.md +153 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_007.md +169 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_008.md +153 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_009.md +144 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_010.md +152 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_011.md +221 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_012.md +318 -0
- package/references/InitializationOrder/StabilityCodeReview_InitializationOrder_001.md +411 -0
- package/references/Lifecycle/StabilityCodeReview_Lifecycle_001.md +255 -0
- package/references/Lifecycle/StabilityCodeReview_Lifecycle_002.md +177 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_001.md +332 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_002.md +261 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_003.md +428 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_004.md +400 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_005.md +364 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_006.md +359 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_007.md +279 -0
- package/references/PROBLEM_TEMPLATE.md +65 -0
- package/references/PerformanceStability/StabilityCodeReview_PerformanceStability_001.md +380 -0
- package/references/PerformanceStability/StabilityCodeReview_PerformanceStability_002.md +437 -0
- package/references/REPORT_TEMPLATE.csv +5 -0
- package/references/REPORT_TEMPLATE.md +132 -0
- package/references/RULE_DEVELOPMENT_GUIDE.md +711 -0
- package/references/RULE_INDEX.md +101 -0
- package/references/RULE_TEMPLATE.md +192 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_001.md +334 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_002.md +425 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_003.md +420 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_004.md +409 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_005.md +445 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_006.md +384 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_007.md +395 -0
- package/scripts/add-rule.py +423 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
---
|
|
2
|
+
rule_id: "StabilityCodeReview_BoundaryCondition_003"
|
|
3
|
+
name: "Parcel数据不可直接作为内存申请大小"
|
|
4
|
+
category: "边界条件"
|
|
5
|
+
severity: "HIGH"
|
|
6
|
+
language: ["cpp", "c++"]
|
|
7
|
+
author: "OH-Department7 Stability Team"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Parcel数据不可直接作为内存申请大小
|
|
11
|
+
|
|
12
|
+
## 问题描述
|
|
13
|
+
|
|
14
|
+
从Parcel中读取的数据不可信,不能直接作为内存申请大小的值,否则可能造成内存超大申请,导致内存耗尽、程序崩溃或拒绝服务攻击。
|
|
15
|
+
|
|
16
|
+
## 检测示例
|
|
17
|
+
|
|
18
|
+
### ❌ 问题代码
|
|
19
|
+
|
|
20
|
+
```cpp
|
|
21
|
+
// 错误示例1:Parcel数据直接用于malloc
|
|
22
|
+
void* AllocateBuffer(Parcel& parcel)
|
|
23
|
+
{
|
|
24
|
+
size_t size = parcel.ReadUint32(); // 不可信数据
|
|
25
|
+
void* buffer = malloc(size); // 危险:size可能为超大值
|
|
26
|
+
return buffer;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 错误示例2:Parcel数据用于new数组
|
|
30
|
+
int* CreateIntArray(Parcel& parcel)
|
|
31
|
+
{
|
|
32
|
+
int count = parcel.ReadInt32();
|
|
33
|
+
int* arr = new int[count]; // 危险:count可能为超大值
|
|
34
|
+
return arr;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 错误示例3:Parcel数据用于std::vector初始化
|
|
38
|
+
std::vector<char> ReadVector(Parcel& parcel)
|
|
39
|
+
{
|
|
40
|
+
uint32_t size = parcel.ReadUint32();
|
|
41
|
+
std::vector<char> vec(size); // 危险:size可能为超大值
|
|
42
|
+
return vec;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 错误示例4:Parcel数据用于std::string分配
|
|
46
|
+
std::string ReadString(Parcel& parcel)
|
|
47
|
+
{
|
|
48
|
+
uint32_t len = parcel.ReadUint32();
|
|
49
|
+
std::string str;
|
|
50
|
+
str.resize(len); // 危险:len可能为超大值
|
|
51
|
+
parcel.ReadBuffer(static_cast<void*>(&str[0]), len);
|
|
52
|
+
return str;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 错误示例5:Parcel数据用于realloc
|
|
56
|
+
void* ResizeBuffer(Parcel& parcel, void* oldPtr, size_t oldSize)
|
|
57
|
+
{
|
|
58
|
+
size_t newSize = parcel.ReadUint32();
|
|
59
|
+
void* newPtr = realloc(oldPtr, newSize); // 危险:newSize可能为超大值
|
|
60
|
+
return newPtr;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 错误示例6:多级内存申请叠加
|
|
64
|
+
void** CreateBufferArray(Parcel& parcel)
|
|
65
|
+
{
|
|
66
|
+
int count = parcel.ReadInt32();
|
|
67
|
+
void** arr = new void*[count]; // 危险1:count可能超大
|
|
68
|
+
for (int i = 0; i < count; i++) {
|
|
69
|
+
size_t bufSize = parcel.ReadUint32();
|
|
70
|
+
arr[i] = malloc(bufSize); // 危险2:bufSize可能超大
|
|
71
|
+
}
|
|
72
|
+
return arr;
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### ✅ 修复方案
|
|
77
|
+
|
|
78
|
+
```cpp
|
|
79
|
+
// 正确示例1:添加上限检查
|
|
80
|
+
constexpr size_t MAX_BUFFER_SIZE = 10 * 1024 * 1024; // 10MB
|
|
81
|
+
|
|
82
|
+
void* AllocateBuffer(Parcel& parcel)
|
|
83
|
+
{
|
|
84
|
+
size_t size = parcel.ReadUint32();
|
|
85
|
+
if (size == 0 || size > MAX_BUFFER_SIZE) {
|
|
86
|
+
LOGE("Invalid buffer size: %zu, max allowed: %zu", size, MAX_BUFFER_SIZE);
|
|
87
|
+
return nullptr;
|
|
88
|
+
}
|
|
89
|
+
void* buffer = malloc(size);
|
|
90
|
+
if (buffer == nullptr) {
|
|
91
|
+
LOGE("malloc failed for size: %zu", size);
|
|
92
|
+
}
|
|
93
|
+
return buffer;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 正确示例2:限制数组大小
|
|
97
|
+
constexpr int MAX_ARRAY_COUNT = 100000;
|
|
98
|
+
|
|
99
|
+
int* CreateIntArray(Parcel& parcel)
|
|
100
|
+
{
|
|
101
|
+
int count = parcel.ReadInt32();
|
|
102
|
+
if (count <= 0 || count > MAX_ARRAY_COUNT) {
|
|
103
|
+
LOGE("Invalid array count: %d, max allowed: %d", count, MAX_ARRAY_COUNT);
|
|
104
|
+
return nullptr;
|
|
105
|
+
}
|
|
106
|
+
int* arr = new (std::nothrow) int[count];
|
|
107
|
+
if (arr == nullptr) {
|
|
108
|
+
LOGE("new failed for count: %d", count);
|
|
109
|
+
}
|
|
110
|
+
return arr;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 正确示例3:安全的vector初始化
|
|
114
|
+
constexpr uint32_t MAX_VECTOR_SIZE = 1024 * 1024; // 1M elements
|
|
115
|
+
|
|
116
|
+
std::vector<char> ReadVector(Parcel& parcel)
|
|
117
|
+
{
|
|
118
|
+
uint32_t size = parcel.ReadUint32();
|
|
119
|
+
if (size == 0 || size > MAX_VECTOR_SIZE) {
|
|
120
|
+
LOGE("Invalid vector size: %u", size);
|
|
121
|
+
return std::vector<char>();
|
|
122
|
+
}
|
|
123
|
+
std::vector<char> vec;
|
|
124
|
+
vec.reserve(size); // 使用reserve而非直接初始化
|
|
125
|
+
return vec;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 正确示例4:安全的string处理
|
|
129
|
+
constexpr uint32_t MAX_STRING_LEN = 1024 * 1024; // 1MB
|
|
130
|
+
|
|
131
|
+
std::string ReadString(Parcel& parcel)
|
|
132
|
+
{
|
|
133
|
+
uint32_t len = parcel.ReadUint32();
|
|
134
|
+
if (len == 0 || len > MAX_STRING_LEN) {
|
|
135
|
+
LOGE("Invalid string length: %u", len);
|
|
136
|
+
return "";
|
|
137
|
+
}
|
|
138
|
+
std::string str;
|
|
139
|
+
str.resize(len);
|
|
140
|
+
if (parcel.ReadBuffer(static_cast<void*>(&str[0]), len) != len) {
|
|
141
|
+
LOGE("Failed to read string data");
|
|
142
|
+
return "";
|
|
143
|
+
}
|
|
144
|
+
return str;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 正确示例5:安全的realloc
|
|
148
|
+
void* ResizeBuffer(Parcel& parcel, void* oldPtr, size_t oldSize)
|
|
149
|
+
{
|
|
150
|
+
size_t newSize = parcel.ReadUint32();
|
|
151
|
+
if (newSize == 0 || newSize > MAX_BUFFER_SIZE) {
|
|
152
|
+
LOGE("Invalid new size: %zu", newSize);
|
|
153
|
+
return oldPtr; // 保持原有指针
|
|
154
|
+
}
|
|
155
|
+
void* newPtr = realloc(oldPtr, newSize);
|
|
156
|
+
if (newPtr == nullptr) {
|
|
157
|
+
LOGE("realloc failed");
|
|
158
|
+
return oldPtr;
|
|
159
|
+
}
|
|
160
|
+
return newPtr;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// 正确示例6:分级内存申请保护
|
|
164
|
+
constexpr int MAX_BUFFER_COUNT = 1000;
|
|
165
|
+
constexpr size_t MAX_INDIVIDUAL_BUFFER_SIZE = 1024 * 1024;
|
|
166
|
+
constexpr size_t MAX_TOTAL_BUFFER_SIZE = 100 * 1024 * 1024; // 100MB total
|
|
167
|
+
|
|
168
|
+
void** CreateBufferArray(Parcel& parcel)
|
|
169
|
+
{
|
|
170
|
+
int count = parcel.ReadInt32();
|
|
171
|
+
if (count <= 0 || count > MAX_BUFFER_COUNT) {
|
|
172
|
+
LOGE("Invalid buffer count: %d", count);
|
|
173
|
+
return nullptr;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
void** arr = new (std::nothrow) void*[count];
|
|
177
|
+
if (arr == nullptr) {
|
|
178
|
+
LOGE("Failed to allocate buffer array");
|
|
179
|
+
return nullptr;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
size_t totalAllocated = 0;
|
|
183
|
+
for (int i = 0; i < count; i++) {
|
|
184
|
+
size_t bufSize = parcel.ReadUint32();
|
|
185
|
+
if (bufSize == 0 || bufSize > MAX_INDIVIDUAL_BUFFER_SIZE) {
|
|
186
|
+
LOGE("Invalid buffer size: %zu", bufSize);
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
totalAllocated += bufSize;
|
|
190
|
+
if (totalAllocated > MAX_TOTAL_BUFFER_SIZE) {
|
|
191
|
+
LOGE("Total allocation exceeded limit");
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
arr[i] = malloc(bufSize);
|
|
195
|
+
}
|
|
196
|
+
return arr;
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## 检测范围
|
|
201
|
+
|
|
202
|
+
检查以下模式:
|
|
203
|
+
|
|
204
|
+
1. Parcel数据用于`malloc/calloc/realloc`
|
|
205
|
+
2. Parcel数据用于`new/new[]`
|
|
206
|
+
3. Parcel数据用于`std::vector`初始化
|
|
207
|
+
4. Parcel数据用于`std::string::resize/reserve`
|
|
208
|
+
5. Parcel数据用于容器`resize/reserve`
|
|
209
|
+
|
|
210
|
+
## 检测要点
|
|
211
|
+
|
|
212
|
+
1. 识别Parcel读取函数:`ReadInt32`, `ReadUint32`, `ReadInt64`, `ReadUint64`
|
|
213
|
+
2. 追踪读取变量到内存申请函数
|
|
214
|
+
3. 检查是否进行了上限保护
|
|
215
|
+
4. 识别`malloc`, `calloc`, `realloc`, `new`, `new[]`, `vector`, `string`等
|
|
216
|
+
5. 排除NOPROTECT标记的代码
|
|
217
|
+
|
|
218
|
+
## 风险流分析(RiskFlow)
|
|
219
|
+
|
|
220
|
+
- **RISK_SOURCE**: Parcel读取的不可信数据
|
|
221
|
+
- **RISK_TYPE**: 内存超大申请
|
|
222
|
+
- **RISK_PATH**: 不可信数据 -> 内存申请大小 -> 内存耗尽
|
|
223
|
+
- **IMPACT_POINT**: 系统资源耗尽、拒绝服务
|
|
224
|
+
|
|
225
|
+
## 影响分析(ImpactAnalysis)
|
|
226
|
+
|
|
227
|
+
- **Trigger**: Parcel数据直接用于内存申请大小
|
|
228
|
+
- **Propagation**: 恶意构造超大数值导致大量内存申请
|
|
229
|
+
- **Consequence**: 内存耗尽、程序崩溃、系统不稳定
|
|
230
|
+
- **Mitigation**: 添加内存申请上限检查,分级限制
|
|
231
|
+
|
|
232
|
+
## 误报排除
|
|
233
|
+
|
|
234
|
+
| 场景 | 识别特征 | 处理方式 |
|
|
235
|
+
|------|----------|----------|
|
|
236
|
+
| NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
|
|
237
|
+
| 已有上限检查 | 存在常量比较或条件判断 | 不报 |
|
|
238
|
+
| 安全分配函数 | 使用自定义安全分配器 | 不报 |
|
|
239
|
+
| 第三方库 | 位于 third_party 目录 | 白名单排除 |
|
|
240
|
+
| 测试代码 | 位于 test 目录 | 自动跳过 |
|
|
241
|
+
## 测试用例
|
|
242
|
+
|
|
243
|
+
### 触发用例(应该报)
|
|
244
|
+
|
|
245
|
+
```cpp
|
|
246
|
+
// test_BoundaryCondition_003_trigger.cpp
|
|
247
|
+
void* trigger_bad_1(Parcel& parcel)
|
|
248
|
+
{
|
|
249
|
+
size_t size = parcel.ReadUint32();
|
|
250
|
+
return malloc(size); // 应该报:无上限检查
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
int* trigger_bad_2(Parcel& parcel)
|
|
254
|
+
{
|
|
255
|
+
int count = parcel.ReadInt32();
|
|
256
|
+
return new int[count]; // 应该报:无上限检查
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
std::vector<int> trigger_bad_3(Parcel& parcel)
|
|
260
|
+
{
|
|
261
|
+
uint32_t size = parcel.ReadUint32();
|
|
262
|
+
return std::vector<int>(size); // 应该报:无上限检查
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
void trigger_bad_4(Parcel& parcel)
|
|
266
|
+
{
|
|
267
|
+
uint32_t len = parcel.ReadUint32();
|
|
268
|
+
std::string str;
|
|
269
|
+
str.resize(len); // 应该报:无上限检查
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### 安全用例(不应该报)
|
|
274
|
+
|
|
275
|
+
```cpp
|
|
276
|
+
// test_BoundaryCondition_003_safe.cpp
|
|
277
|
+
constexpr size_t MAX_SIZE = 10 * 1024 * 1024;
|
|
278
|
+
|
|
279
|
+
void* safe_good_1(Parcel& parcel)
|
|
280
|
+
{
|
|
281
|
+
size_t size = parcel.ReadUint32();
|
|
282
|
+
if (size == 0 || size > MAX_SIZE) { // 安全:有上限检查
|
|
283
|
+
LOGE("Invalid size");
|
|
284
|
+
return nullptr;
|
|
285
|
+
}
|
|
286
|
+
return malloc(size);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
int* safe_good_2(Parcel& parcel)
|
|
290
|
+
{
|
|
291
|
+
int count = parcel.ReadInt32();
|
|
292
|
+
if (count <= 0 || count > 1000) { // 安全:有上限检查
|
|
293
|
+
LOGE("Invalid count");
|
|
294
|
+
return nullptr;
|
|
295
|
+
}
|
|
296
|
+
return new (std::nothrow) int[count];
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// NOPROTECT: 特殊场景需要大内存
|
|
300
|
+
void* noprotect_case(Parcel& parcel)
|
|
301
|
+
{
|
|
302
|
+
size_t size = parcel.ReadUint32();
|
|
303
|
+
return malloc(size);
|
|
304
|
+
}
|
|
305
|
+
```
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
---
|
|
2
|
+
rule_id: "StabilityCodeReview_BoundaryCondition_004"
|
|
3
|
+
name: "容器size增长的对外接口应限制上限"
|
|
4
|
+
category: "边界条件"
|
|
5
|
+
severity: "HIGH"
|
|
6
|
+
language: ["cpp", "c++"]
|
|
7
|
+
author: "OH-Department7 Stability Team"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# 容器size增长的对外接口应限制上限
|
|
11
|
+
|
|
12
|
+
## 问题描述
|
|
13
|
+
|
|
14
|
+
会导致容器size增大的对外接口,应该限制容器size的上限,防止外部恶意攻击申请过大内存。外部输入可能包含恶意构造的数据,导致容器无限增长,造成内存耗尽或拒绝服务。
|
|
15
|
+
|
|
16
|
+
## 检测示例
|
|
17
|
+
|
|
18
|
+
### ❌ 问题代码
|
|
19
|
+
|
|
20
|
+
```cpp
|
|
21
|
+
// 错误示例1:push_back无限制
|
|
22
|
+
class DataProcessor {
|
|
23
|
+
private:
|
|
24
|
+
std::vector<int> data_;
|
|
25
|
+
public:
|
|
26
|
+
void AddData(int value) {
|
|
27
|
+
data_.push_back(value); // 危险:无大小限制
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// 错误示例2:从外部数据源批量添加
|
|
32
|
+
class MessageHandler {
|
|
33
|
+
private:
|
|
34
|
+
std::vector<Message> messages_;
|
|
35
|
+
public:
|
|
36
|
+
void AddMessages(const std::vector<Message>& msgs) {
|
|
37
|
+
for (const auto& msg : msgs) {
|
|
38
|
+
messages_.push_back(msg); // 危险:无大小限制
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// 错误示例3:insert操作无限制
|
|
44
|
+
class ConnectionManager {
|
|
45
|
+
private:
|
|
46
|
+
std::set<Connection*> connections_;
|
|
47
|
+
public:
|
|
48
|
+
void AddConnection(Connection* conn) {
|
|
49
|
+
connections_.insert(conn); // 危险:无大小限制
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// 错误示例4:从Parcel读取无限制
|
|
54
|
+
class DataManager {
|
|
55
|
+
private:
|
|
56
|
+
std::vector<std::string> items_;
|
|
57
|
+
public:
|
|
58
|
+
void ReadFromParcel(Parcel& parcel) {
|
|
59
|
+
int count = parcel.ReadInt32();
|
|
60
|
+
for (int i = 0; i < count; i++) {
|
|
61
|
+
items_.push_back(parcel.ReadString()); // 危险:count和items_都无限制
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// 错误示例5:map插入无限制
|
|
67
|
+
class CacheManager {
|
|
68
|
+
private:
|
|
69
|
+
std::map<int, Data> cache_;
|
|
70
|
+
public:
|
|
71
|
+
void Insert(int key, const Data& data) {
|
|
72
|
+
cache_[key] = data; // 危险:无大小限制
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// 错误示例6:链表无限制增长
|
|
77
|
+
class EventQueue {
|
|
78
|
+
private:
|
|
79
|
+
std::list<Event> events_;
|
|
80
|
+
public:
|
|
81
|
+
void PushEvent(const Event& event) {
|
|
82
|
+
events_.push_back(event); // 危险:无大小限制
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### ✅ 修复方案
|
|
88
|
+
|
|
89
|
+
```cpp
|
|
90
|
+
// 正确示例1:添加容量限制
|
|
91
|
+
class DataProcessor {
|
|
92
|
+
private:
|
|
93
|
+
std::vector<int> data_;
|
|
94
|
+
static constexpr size_t MAX_DATA_SIZE = 10000;
|
|
95
|
+
|
|
96
|
+
public:
|
|
97
|
+
bool AddData(int value) {
|
|
98
|
+
if (data_.size() >= MAX_DATA_SIZE) {
|
|
99
|
+
LOGE("Data size exceeded limit: %zu", MAX_DATA_SIZE);
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
data_.push_back(value);
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// 正确示例2:批量添加时检查总大小
|
|
108
|
+
class MessageHandler {
|
|
109
|
+
private:
|
|
110
|
+
std::vector<Message> messages_;
|
|
111
|
+
static constexpr size_t MAX_MESSAGES = 5000;
|
|
112
|
+
|
|
113
|
+
public:
|
|
114
|
+
bool AddMessages(const std::vector<Message>& msgs) {
|
|
115
|
+
if (messages_.size() + msgs.size() > MAX_MESSAGES) {
|
|
116
|
+
LOGE("Message count exceeded limit");
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
for (const auto& msg : msgs) {
|
|
120
|
+
messages_.push_back(msg);
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// 正确示例3:连接数限制
|
|
127
|
+
class ConnectionManager {
|
|
128
|
+
private:
|
|
129
|
+
std::set<Connection*> connections_;
|
|
130
|
+
static constexpr size_t MAX_CONNECTIONS = 1000;
|
|
131
|
+
|
|
132
|
+
public:
|
|
133
|
+
bool AddConnection(Connection* conn) {
|
|
134
|
+
if (connections_.size() >= MAX_CONNECTIONS) {
|
|
135
|
+
LOGE("Connection count exceeded limit: %zu", MAX_CONNECTIONS);
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
auto result = connections_.insert(conn);
|
|
139
|
+
if (!result.second) {
|
|
140
|
+
LOGE("Connection already exists");
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// 正确示例4:安全的Parcel读取
|
|
148
|
+
class DataManager {
|
|
149
|
+
private:
|
|
150
|
+
std::vector<std::string> items_;
|
|
151
|
+
static constexpr size_t MAX_ITEMS = 1000;
|
|
152
|
+
static constexpr size_t MAX_ITEM_COUNT = 100;
|
|
153
|
+
|
|
154
|
+
public:
|
|
155
|
+
bool ReadFromParcel(Parcel& parcel) {
|
|
156
|
+
int count = parcel.ReadInt32();
|
|
157
|
+
if (count < 0 || static_cast<size_t>(count) > MAX_ITEM_COUNT) {
|
|
158
|
+
LOGE("Invalid count: %d", count);
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
if (items_.size() + count > MAX_ITEMS) {
|
|
162
|
+
LOGE("Items size exceeded limit");
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
for (int i = 0; i < count; i++) {
|
|
166
|
+
items_.push_back(parcel.ReadString());
|
|
167
|
+
}
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// 正确示例5:缓存大小限制
|
|
173
|
+
class CacheManager {
|
|
174
|
+
private:
|
|
175
|
+
std::map<int, Data> cache_;
|
|
176
|
+
static constexpr size_t MAX_CACHE_SIZE = 10000;
|
|
177
|
+
|
|
178
|
+
public:
|
|
179
|
+
bool Insert(int key, const Data& data) {
|
|
180
|
+
if (cache_.size() >= MAX_CACHE_SIZE) {
|
|
181
|
+
// 可选:淘汰策略
|
|
182
|
+
EvictOldest();
|
|
183
|
+
}
|
|
184
|
+
if (cache_.size() >= MAX_CACHE_SIZE) {
|
|
185
|
+
LOGE("Cache is full");
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
cache_[key] = data;
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private:
|
|
193
|
+
void EvictOldest() {
|
|
194
|
+
if (!cache_.empty()) {
|
|
195
|
+
cache_.erase(cache_.begin());
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// 正确示例6:事件队列大小限制
|
|
201
|
+
class EventQueue {
|
|
202
|
+
private:
|
|
203
|
+
std::list<Event> events_;
|
|
204
|
+
static constexpr size_t MAX_QUEUE_SIZE = 10000;
|
|
205
|
+
|
|
206
|
+
public:
|
|
207
|
+
bool PushEvent(const Event& event) {
|
|
208
|
+
if (events_.size() >= MAX_QUEUE_SIZE) {
|
|
209
|
+
LOGE("Event queue is full, dropping oldest event");
|
|
210
|
+
events_.pop_front();
|
|
211
|
+
}
|
|
212
|
+
events_.push_back(event);
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
bool PushEventNoDrop(const Event& event) {
|
|
217
|
+
if (events_.size() >= MAX_QUEUE_SIZE) {
|
|
218
|
+
LOGE("Event queue is full");
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
events_.push_back(event);
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## 检测范围
|
|
228
|
+
|
|
229
|
+
检查以下模式:
|
|
230
|
+
|
|
231
|
+
1. 公共接口中的`push_back/push_front/insert/emplace`
|
|
232
|
+
2. 公共接口中的容器扩展操作
|
|
233
|
+
3. 公共接口从外部数据源添加元素
|
|
234
|
+
4. 公共接口处理批量数据
|
|
235
|
+
|
|
236
|
+
## 检测要点
|
|
237
|
+
|
|
238
|
+
1. 识别`public`成员函数中的容器操作
|
|
239
|
+
2. 检测`push_back`, `push_front`, `insert`, `emplace`等操作
|
|
240
|
+
3. 检查是否进行了大小限制
|
|
241
|
+
4. 识别`std::vector`, `std::list`, `std::map`, `std::set`, `std::deque`等容器
|
|
242
|
+
5. 排除NOPROTECT标记的代码
|
|
243
|
+
|
|
244
|
+
## 风险流分析(RiskFlow)
|
|
245
|
+
|
|
246
|
+
- **RISK_SOURCE**: 外部输入数据
|
|
247
|
+
- **RISK_TYPE**: 容器大小无限制
|
|
248
|
+
- **RISK_PATH**: 外部数据 -> 容器增长 -> 内存耗尽
|
|
249
|
+
- **IMPACT_POINT**: 系统资源耗尽、拒绝服务
|
|
250
|
+
|
|
251
|
+
## 影响分析(ImpactAnalysis)
|
|
252
|
+
|
|
253
|
+
- **Trigger**: 对外接口未限制容器大小增长
|
|
254
|
+
- **Propagation**: 恶意大量调用导致容器无限增长
|
|
255
|
+
- **Consequence**: 内存耗尽、程序崩溃、系统不稳定
|
|
256
|
+
- **Mitigation**: 添加容器大小上限检查,实现淘汰策略
|
|
257
|
+
|
|
258
|
+
## 误报排除
|
|
259
|
+
|
|
260
|
+
| 场景 | 识别特征 | 处理方式 |
|
|
261
|
+
|------|----------|----------|
|
|
262
|
+
| NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
|
|
263
|
+
| 已有大小检查 | 存在 size() 比较或容量检查 | 不报 |
|
|
264
|
+
| 私有成员函数 | 标记为 private/protected | 不报 |
|
|
265
|
+
| 内部工具类 | 明确标记为内部使用 | 不报 |
|
|
266
|
+
| 第三方库 | 位于 third_party 目录 | 白名单排除 |
|
|
267
|
+
## 测试用例
|
|
268
|
+
|
|
269
|
+
### 触发用例(应该报)
|
|
270
|
+
|
|
271
|
+
```cpp
|
|
272
|
+
// test_BoundaryCondition_004_trigger.cpp
|
|
273
|
+
class TriggerBad1 {
|
|
274
|
+
std::vector<int> data_;
|
|
275
|
+
public:
|
|
276
|
+
void AddData(int value) {
|
|
277
|
+
data_.push_back(value); // 应该报:无大小限制
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
class TriggerBad2 {
|
|
282
|
+
std::map<int, std::string> cache_;
|
|
283
|
+
public:
|
|
284
|
+
void Insert(int key, const std::string& value) {
|
|
285
|
+
cache_[key] = value; // 应该报:无大小限制
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
class TriggerBad3 {
|
|
290
|
+
std::list<Event> events_;
|
|
291
|
+
public:
|
|
292
|
+
void PushEvent(const Event& event) {
|
|
293
|
+
events_.push_back(event); // 应该报:无大小限制
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
class TriggerBad4 {
|
|
298
|
+
std::set<int> ids_;
|
|
299
|
+
public:
|
|
300
|
+
void AddId(int id) {
|
|
301
|
+
ids_.insert(id); // 应该报:无大小限制
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### 安全用例(不应该报)
|
|
307
|
+
|
|
308
|
+
```cpp
|
|
309
|
+
// test_BoundaryCondition_004_safe.cpp
|
|
310
|
+
class SafeGood1 {
|
|
311
|
+
std::vector<int> data_;
|
|
312
|
+
static constexpr size_t MAX_SIZE = 1000;
|
|
313
|
+
public:
|
|
314
|
+
bool AddData(int value) {
|
|
315
|
+
if (data_.size() >= MAX_SIZE) { // 安全:有大小限制
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
data_.push_back(value);
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
class SafeGood2 {
|
|
324
|
+
std::vector<int> data_;
|
|
325
|
+
public:
|
|
326
|
+
void AddData(int value) {
|
|
327
|
+
if (data_.capacity() > data_.size()) { // 安全:有容量检查
|
|
328
|
+
data_.push_back(value);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
class SafeGood3 {
|
|
334
|
+
std::vector<int> data_;
|
|
335
|
+
public:
|
|
336
|
+
void ClearAndAdd(int value) { // 安全:先清空
|
|
337
|
+
data_.clear();
|
|
338
|
+
data_.push_back(value);
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// NOPROTECT: 内部使用,数据量可控
|
|
343
|
+
class NoprotectCase {
|
|
344
|
+
std::vector<int> data_;
|
|
345
|
+
public:
|
|
346
|
+
void AddData(int value) {
|
|
347
|
+
data_.push_back(value);
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
```
|