svf-tools 1.0.988 → 1.0.990
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/package.json +1 -1
- package/svf/include/AE/Svfexe/AEDetector.h +15 -2
- package/svf/include/AE/Svfexe/AbsExtAPI.h +147 -0
- package/svf/include/AE/Svfexe/AbstractInterpretation.h +71 -92
- package/svf/lib/AE/Svfexe/AEDetector.cpp +107 -27
- package/svf/lib/AE/Svfexe/AbsExtAPI.cpp +765 -0
- package/svf/lib/AE/Svfexe/AbstractInterpretation.cpp +24 -845
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svf-tools",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.990",
|
|
4
4
|
"description": "* <b>[TypeClone](https://github.com/SVF-tools/SVF/wiki/TypeClone) published in our [ECOOP paper](https://yuleisui.github.io/publications/ecoop20.pdf) is now available in SVF </b> * <b>SVF now uses a single script for its build. Just type [`source ./build.sh`](https://github.com/SVF-tools/SVF/blob/master/build.sh) in your terminal, that's it!</b> * <b>SVF now supports LLVM-10.0.0! </b> * <b>We thank [bsauce](https://github.com/bsauce) for writing a user manual of SVF ([link1](https://www.jianshu.com/p/068a08ec749c) and [link2](https://www.jianshu.com/p/777c30d4240e)) in Chinese </b> * <b>SVF now supports LLVM-9.0.0 (Thank [Byoungyoung Lee](https://github.com/SVF-tools/SVF/issues/142) for his help!). </b> * <b>SVF now supports a set of [field-sensitive pointer analyses](https://yuleisui.github.io/publications/sas2019a.pdf). </b> * <b>[Use SVF as an external lib](https://github.com/SVF-tools/SVF/wiki/Using-SVF-as-a-lib-in-your-own-tool) for your own project (Contributed by [Hongxu Chen](https://github.com/HongxuChen)). </b> * <b>SVF now supports LLVM-7.0.0. </b> * <b>SVF now supports Docker. [Try SVF in Docker](https://github.com/SVF-tools/SVF/wiki/Try-SVF-in-Docker)! </b> * <b>SVF now supports [LLVM-6.0.0](https://github.com/svf-tools/SVF/pull/38) (Contributed by [Jack Anthony](https://github.com/jackanth)). </b> * <b>SVF now supports [LLVM-4.0.0](https://github.com/svf-tools/SVF/pull/23) (Contributed by Jared Carlson. Thank [Jared](https://github.com/jcarlson23) and [Will](https://github.com/dtzWill) for their in-depth [discussions](https://github.com/svf-tools/SVF/pull/18) about updating SVF!) </b> * <b>SVF now supports analysis for C++ programs.</b> <br />",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -75,6 +75,12 @@ public:
|
|
|
75
75
|
*/
|
|
76
76
|
virtual void detect(AbstractState& as, const ICFGNode* node) = 0;
|
|
77
77
|
|
|
78
|
+
/**
|
|
79
|
+
* @brief Pure virtual function for handling stub external API calls. (e.g. UNSAFE_BUFACCESS)
|
|
80
|
+
* @param call Pointer to the ext call ICFG node.
|
|
81
|
+
*/
|
|
82
|
+
virtual void handleStubFunctions(const CallICFGNode* call) = 0;
|
|
83
|
+
|
|
78
84
|
/**
|
|
79
85
|
* @brief Pure virtual function to report detected bugs.
|
|
80
86
|
*/
|
|
@@ -169,6 +175,13 @@ public:
|
|
|
169
175
|
*/
|
|
170
176
|
void detect(AbstractState& as, const ICFGNode*);
|
|
171
177
|
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* @brief Handles external API calls related to buffer overflow detection.
|
|
181
|
+
* @param call Pointer to the call ICFG node.
|
|
182
|
+
*/
|
|
183
|
+
void handleStubFunctions(const CallICFGNode*);
|
|
184
|
+
|
|
172
185
|
/**
|
|
173
186
|
* @brief Adds an offset to a GEP object.
|
|
174
187
|
* @param obj Pointer to the GEP object.
|
|
@@ -277,11 +290,11 @@ public:
|
|
|
277
290
|
/**
|
|
278
291
|
* @brief Checks if memory can be safely accessed.
|
|
279
292
|
* @param as Reference to the abstract state.
|
|
280
|
-
* @param value Pointer to the SVF
|
|
293
|
+
* @param value Pointer to the SVF var.
|
|
281
294
|
* @param len The interval value representing the length of the memory access.
|
|
282
295
|
* @return True if the memory access is safe, false otherwise.
|
|
283
296
|
*/
|
|
284
|
-
bool canSafelyAccessMemory(AbstractState& as, const
|
|
297
|
+
bool canSafelyAccessMemory(AbstractState& as, const SVFVar *value, const IntervalValue &len);
|
|
285
298
|
|
|
286
299
|
private:
|
|
287
300
|
/**
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
//===- AbsExtAPI.h -- Abstract Interpretation External API handler-----//
|
|
2
|
+
//
|
|
3
|
+
// SVF: Static Value-Flow Analysis
|
|
4
|
+
//
|
|
5
|
+
// Copyright (C) <2013-> <Yulei Sui>
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
// This program is free software: you can redistribute it and/or modify
|
|
9
|
+
// it under the terms of the GNU Affero General Public License as published by
|
|
10
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
11
|
+
// (at your option) any later version.
|
|
12
|
+
|
|
13
|
+
// This program is distributed in the hope that it will be useful,
|
|
14
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
// GNU Affero General Public License for more details.
|
|
17
|
+
|
|
18
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
19
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
20
|
+
//
|
|
21
|
+
//===----------------------------------------------------------------------===//
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
//
|
|
25
|
+
// Created by Jiawei Wang on 2024/9/9.
|
|
26
|
+
//
|
|
27
|
+
#pragma once
|
|
28
|
+
#include "AE/Core/AbstractState.h"
|
|
29
|
+
#include "AE/Core/ICFGWTO.h"
|
|
30
|
+
#include "AE/Svfexe/AEDetector.h"
|
|
31
|
+
#include "AE/Svfexe/AbsExtAPI.h"
|
|
32
|
+
#include "Util/SVFBugReport.h"
|
|
33
|
+
#include "WPA/Andersen.h"
|
|
34
|
+
|
|
35
|
+
namespace SVF
|
|
36
|
+
{
|
|
37
|
+
|
|
38
|
+
// Forward declaration of AbstractInterpretation class
|
|
39
|
+
class AbstractInterpretation;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @class AbsExtAPI
|
|
43
|
+
* @brief Handles external API calls and manages abstract states.
|
|
44
|
+
*/
|
|
45
|
+
class AbsExtAPI
|
|
46
|
+
{
|
|
47
|
+
public:
|
|
48
|
+
/**
|
|
49
|
+
* @enum ExtAPIType
|
|
50
|
+
* @brief Enumeration of external API types.
|
|
51
|
+
*/
|
|
52
|
+
enum ExtAPIType { UNCLASSIFIED, MEMCPY, MEMSET, STRCPY, STRCAT };
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @brief Constructor for AbsExtAPI.
|
|
56
|
+
* @param abstractTrace Reference to a map of ICFG nodes to abstract states.
|
|
57
|
+
*/
|
|
58
|
+
AbsExtAPI(Map<const ICFGNode*, AbstractState>& traces);
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @brief Initializes the external function map.
|
|
62
|
+
*/
|
|
63
|
+
void initExtFunMap();
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @brief Reads a string from the abstract state.
|
|
67
|
+
* @param as Reference to the abstract state.
|
|
68
|
+
* @param rhs Pointer to the SVF variable representing the string.
|
|
69
|
+
* @return The string value.
|
|
70
|
+
*/
|
|
71
|
+
std::string strRead(AbstractState& as, const SVFVar* rhs);
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @brief Handles an external API call.
|
|
75
|
+
* @param call Pointer to the call ICFG node.
|
|
76
|
+
*/
|
|
77
|
+
void handleExtAPI(const CallICFGNode *call);
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @brief Handles the strcpy API call.
|
|
81
|
+
* @param call Pointer to the call ICFG node.
|
|
82
|
+
*/
|
|
83
|
+
void handleStrcpy(const CallICFGNode *call);
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @brief Calculates the length of a string.
|
|
87
|
+
* @param as Reference to the abstract state.
|
|
88
|
+
* @param strValue Pointer to the SVF variable representing the string.
|
|
89
|
+
* @return The interval value representing the string length.
|
|
90
|
+
*/
|
|
91
|
+
IntervalValue getStrlen(AbstractState& as, const SVF::SVFVar *strValue);
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @brief Handles the strcat API call.
|
|
95
|
+
* @param call Pointer to the call ICFG node.
|
|
96
|
+
*/
|
|
97
|
+
void handleStrcat(const SVF::CallICFGNode *call);
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @brief Handles the memcpy API call.
|
|
101
|
+
* @param as Reference to the abstract state.
|
|
102
|
+
* @param dst Pointer to the destination SVF variable.
|
|
103
|
+
* @param src Pointer to the source SVF variable.
|
|
104
|
+
* @param len The interval value representing the length to copy.
|
|
105
|
+
* @param start_idx The starting index for copying.
|
|
106
|
+
*/
|
|
107
|
+
void handleMemcpy(AbstractState& as, const SVF::SVFVar *dst, const SVF::SVFVar *src, IntervalValue len, u32_t start_idx);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @brief Handles the memset API call.
|
|
111
|
+
* @param as Reference to the abstract state.
|
|
112
|
+
* @param dst Pointer to the destination SVF variable.
|
|
113
|
+
* @param elem The interval value representing the element to set.
|
|
114
|
+
* @param len The interval value representing the length to set.
|
|
115
|
+
*/
|
|
116
|
+
void handleMemset(AbstractState& as, const SVFVar* dst, IntervalValue elem, IntervalValue len);
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @brief Gets the range limit from a type.
|
|
120
|
+
* @param type Pointer to the SVF type.
|
|
121
|
+
* @return The interval value representing the range limit.
|
|
122
|
+
*/
|
|
123
|
+
IntervalValue getRangeLimitFromType(const SVFType* type);
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @brief Retrieves the abstract state from the trace for a given ICFG node.
|
|
127
|
+
* @param node Pointer to the ICFG node.
|
|
128
|
+
* @return Reference to the abstract state.
|
|
129
|
+
* @throws Assertion if no trace exists for the node.
|
|
130
|
+
*/
|
|
131
|
+
AbstractState& getAbsStateFromTrace(const ICFGNode* node);
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @brief Retrieves the SVF variable from a given SVF value.
|
|
135
|
+
* @param val Pointer to the SVF value.
|
|
136
|
+
* @return Pointer to the corresponding SVF variable.
|
|
137
|
+
*/
|
|
138
|
+
const SVFVar* getSVFVar(const SVFValue* val);
|
|
139
|
+
|
|
140
|
+
protected:
|
|
141
|
+
SVFIR* svfir; ///< Pointer to the SVF intermediate representation.
|
|
142
|
+
ICFG* icfg; ///< Pointer to the interprocedural control flow graph.
|
|
143
|
+
Map<const ICFGNode*, AbstractState>& abstractTrace; ///< Map of ICFG nodes to abstract states.
|
|
144
|
+
Map<std::string, std::function<void(const CallICFGNode*)>> func_map; ///< Map of function names to handlers.
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
} // namespace SVF
|
|
@@ -31,12 +31,14 @@
|
|
|
31
31
|
#include "AE/Core/AbstractState.h"
|
|
32
32
|
#include "AE/Core/ICFGWTO.h"
|
|
33
33
|
#include "AE/Svfexe/AEDetector.h"
|
|
34
|
+
#include "AE/Svfexe/AbsExtAPI.h"
|
|
34
35
|
#include "Util/SVFBugReport.h"
|
|
35
36
|
#include "WPA/Andersen.h"
|
|
36
37
|
|
|
37
38
|
namespace SVF
|
|
38
39
|
{
|
|
39
40
|
class AbstractInterpretation;
|
|
41
|
+
class AbsExtAPI;
|
|
40
42
|
class AEStat;
|
|
41
43
|
class AEAPI;
|
|
42
44
|
|
|
@@ -104,7 +106,6 @@ class AbstractInterpretation
|
|
|
104
106
|
friend class BufOverflowDetector;
|
|
105
107
|
|
|
106
108
|
public:
|
|
107
|
-
enum ExtAPIType { UNCLASSIFIED, MEMCPY, MEMSET, STRCPY, STRCAT };
|
|
108
109
|
typedef SCCDetection<CallGraph*> CallGraphSCC;
|
|
109
110
|
/// Constructor
|
|
110
111
|
AbstractInterpretation();
|
|
@@ -128,7 +129,9 @@ public:
|
|
|
128
129
|
detectors.push_back(std::move(detector));
|
|
129
130
|
}
|
|
130
131
|
|
|
131
|
-
|
|
132
|
+
Set<const CallICFGNode*> checkpoints; // for CI check
|
|
133
|
+
|
|
134
|
+
private:
|
|
132
135
|
/// Global ICFGNode is handled at the entry of the program,
|
|
133
136
|
virtual void handleGlobalNode();
|
|
134
137
|
|
|
@@ -213,77 +216,6 @@ protected:
|
|
|
213
216
|
AbstractState& as);
|
|
214
217
|
|
|
215
218
|
|
|
216
|
-
/**
|
|
217
|
-
* handle external function call
|
|
218
|
-
*
|
|
219
|
-
* @param call call node whose callee is external function
|
|
220
|
-
*/
|
|
221
|
-
virtual void handleExtAPI(const CallICFGNode *call);
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* the map of external function to its API type
|
|
225
|
-
*
|
|
226
|
-
* In AEAPI, this function is mainly used for abstract explanation.
|
|
227
|
-
* In subclasses, this function is mainly used to check specific bugs
|
|
228
|
-
*/
|
|
229
|
-
virtual void initExtFunMap();
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* get byte size of alloca inst
|
|
234
|
-
* e.g. source code str = "abc", there are str value, return "abc"
|
|
235
|
-
*
|
|
236
|
-
* @param rhs SVFValue of string
|
|
237
|
-
* @return the string
|
|
238
|
-
*/
|
|
239
|
-
std::string strRead(AbstractState& as,const SVFValue* rhs);
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* get length of string
|
|
243
|
-
* e.g. source code str = "abc", return 3
|
|
244
|
-
*
|
|
245
|
-
* @param strValue SVFValue of string
|
|
246
|
-
* @return IntervalValue of string length
|
|
247
|
-
*/
|
|
248
|
-
IntervalValue getStrlen(AbstractState& as, const SVF::SVFValue *strValue);
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* execute strcpy in abstract execution
|
|
252
|
-
* e.g arr = new char[10]
|
|
253
|
-
* str = "abc"
|
|
254
|
-
* strcpy(arr, str)
|
|
255
|
-
* we can set arr[0]='a', arr[1]='b', arr[2]='c', arr[3]='\0'
|
|
256
|
-
* @param call callnode of strcpy like api
|
|
257
|
-
*/
|
|
258
|
-
virtual void handleStrcpy(const CallICFGNode *call);
|
|
259
|
-
/**
|
|
260
|
-
* execute strcpy in abstract execution
|
|
261
|
-
* e.g arr[10] = "abc"
|
|
262
|
-
* str = "de"
|
|
263
|
-
* strcat(arr, str)
|
|
264
|
-
* we can set arr[3]='d', arr[4]='e', arr[5]='\0'
|
|
265
|
-
* @param call callnode of strcat like api
|
|
266
|
-
*/
|
|
267
|
-
virtual void handleStrcat(const CallICFGNode *call);
|
|
268
|
-
/**
|
|
269
|
-
* execute memcpy in abstract execution
|
|
270
|
-
* e.g arr = new char[10]
|
|
271
|
-
* str = "abcd"
|
|
272
|
-
* memcpy(arr, str, 5)
|
|
273
|
-
* we can set arr[3]='d', arr[4]='e', arr[5]='\0'
|
|
274
|
-
* @param call callnode of memcpy like api
|
|
275
|
-
*/
|
|
276
|
-
virtual void handleMemcpy(AbstractState& as, const SVFValue* dst, const SVFValue* src, IntervalValue len, u32_t start_idx);
|
|
277
|
-
/**
|
|
278
|
-
* execute memset in abstract execution
|
|
279
|
-
* e.g arr = new char[10]
|
|
280
|
-
* memset(arr, 'c', 2)
|
|
281
|
-
* we can set arr[0]='c', arr[1]='c', arr[2]='\0'
|
|
282
|
-
* @param call callnode of memset like api
|
|
283
|
-
*/
|
|
284
|
-
virtual void handleMemset(AbstractState& as, const SVFValue* dst, IntervalValue elem, IntervalValue len);
|
|
285
|
-
|
|
286
|
-
|
|
287
219
|
void collectCheckPoint();
|
|
288
220
|
void checkPointAllSet();
|
|
289
221
|
|
|
@@ -309,8 +241,6 @@ protected:
|
|
|
309
241
|
|
|
310
242
|
void updateStateOnPhi(const PhiStmt *phi);
|
|
311
243
|
|
|
312
|
-
IntervalValue getRangeLimitFromType(const SVFType* type);
|
|
313
|
-
|
|
314
244
|
|
|
315
245
|
/// protected data members, also used in subclasses
|
|
316
246
|
SVFIR* svfir;
|
|
@@ -324,18 +254,6 @@ protected:
|
|
|
324
254
|
Map<const SVFFunction*, ICFGWTO*> funcToWTO;
|
|
325
255
|
Set<const SVFFunction*> recursiveFuns;
|
|
326
256
|
|
|
327
|
-
private:
|
|
328
|
-
// helper functions in handleCallSite
|
|
329
|
-
virtual bool isExtCall(const CallICFGNode* callNode);
|
|
330
|
-
virtual void extCallPass(const CallICFGNode* callNode);
|
|
331
|
-
virtual bool isRecursiveCall(const CallICFGNode* callNode);
|
|
332
|
-
virtual void recursiveCallPass(const CallICFGNode* callNode);
|
|
333
|
-
virtual bool isDirectCall(const CallICFGNode* callNode);
|
|
334
|
-
virtual void directCallFunPass(const CallICFGNode* callNode);
|
|
335
|
-
virtual bool isIndirectCall(const CallICFGNode* callNode);
|
|
336
|
-
virtual void indirectCallFunPass(const CallICFGNode* callNode);
|
|
337
|
-
|
|
338
|
-
protected:
|
|
339
257
|
|
|
340
258
|
AbstractState& getAbsStateFromTrace(const ICFGNode* node)
|
|
341
259
|
{
|
|
@@ -356,16 +274,77 @@ protected:
|
|
|
356
274
|
return abstractTrace.count(repNode) != 0;
|
|
357
275
|
}
|
|
358
276
|
|
|
359
|
-
|
|
277
|
+
AbsExtAPI* getUtils()
|
|
278
|
+
{
|
|
279
|
+
return utils;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// helper functions in handleCallSite
|
|
283
|
+
virtual bool isExtCall(const CallICFGNode* callNode);
|
|
284
|
+
virtual void extCallPass(const CallICFGNode* callNode);
|
|
285
|
+
virtual bool isRecursiveCall(const CallICFGNode* callNode);
|
|
286
|
+
virtual void recursiveCallPass(const CallICFGNode* callNode);
|
|
287
|
+
virtual bool isDirectCall(const CallICFGNode* callNode);
|
|
288
|
+
virtual void directCallFunPass(const CallICFGNode* callNode);
|
|
289
|
+
virtual bool isIndirectCall(const CallICFGNode* callNode);
|
|
290
|
+
virtual void indirectCallFunPass(const CallICFGNode* callNode);
|
|
291
|
+
|
|
360
292
|
// there data should be shared with subclasses
|
|
361
293
|
Map<std::string, std::function<void(const CallICFGNode*)>> func_map;
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
Map<const ICFGNode*, AbstractState>
|
|
365
|
-
abstractTrace; // abstract states immediately after nodes
|
|
294
|
+
|
|
295
|
+
Map<const ICFGNode*, AbstractState> abstractTrace; // abstract states immediately after nodes
|
|
366
296
|
std::string moduleName;
|
|
367
297
|
|
|
368
298
|
std::vector<std::unique_ptr<AEDetector>> detectors;
|
|
299
|
+
AbsExtAPI* utils;
|
|
300
|
+
|
|
301
|
+
// according to varieties of cmp insts,
|
|
302
|
+
// maybe var X var, var X const, const X var, const X const
|
|
303
|
+
// we accept 'var X const' 'var X var' 'const X const'
|
|
304
|
+
// if 'const X var', we need to reverse op0 op1 and its predicate 'var X' const'
|
|
305
|
+
// X' is reverse predicate of X
|
|
306
|
+
// == -> !=, != -> ==, > -> <=, >= -> <, < -> >=, <= -> >
|
|
307
|
+
|
|
308
|
+
Map<s32_t, s32_t> _reverse_predicate =
|
|
309
|
+
{
|
|
310
|
+
{CmpStmt::Predicate::FCMP_OEQ, CmpStmt::Predicate::FCMP_ONE}, // == -> !=
|
|
311
|
+
{CmpStmt::Predicate::FCMP_UEQ, CmpStmt::Predicate::FCMP_UNE}, // == -> !=
|
|
312
|
+
{CmpStmt::Predicate::FCMP_OGT, CmpStmt::Predicate::FCMP_OLE}, // > -> <=
|
|
313
|
+
{CmpStmt::Predicate::FCMP_OGE, CmpStmt::Predicate::FCMP_OLT}, // >= -> <
|
|
314
|
+
{CmpStmt::Predicate::FCMP_OLT, CmpStmt::Predicate::FCMP_OGE}, // < -> >=
|
|
315
|
+
{CmpStmt::Predicate::FCMP_OLE, CmpStmt::Predicate::FCMP_OGT}, // <= -> >
|
|
316
|
+
{CmpStmt::Predicate::FCMP_ONE, CmpStmt::Predicate::FCMP_OEQ}, // != -> ==
|
|
317
|
+
{CmpStmt::Predicate::FCMP_UNE, CmpStmt::Predicate::FCMP_UEQ}, // != -> ==
|
|
318
|
+
{CmpStmt::Predicate::ICMP_EQ, CmpStmt::Predicate::ICMP_NE}, // == -> !=
|
|
319
|
+
{CmpStmt::Predicate::ICMP_NE, CmpStmt::Predicate::ICMP_EQ}, // != -> ==
|
|
320
|
+
{CmpStmt::Predicate::ICMP_UGT, CmpStmt::Predicate::ICMP_ULE}, // > -> <=
|
|
321
|
+
{CmpStmt::Predicate::ICMP_ULT, CmpStmt::Predicate::ICMP_UGE}, // < -> >=
|
|
322
|
+
{CmpStmt::Predicate::ICMP_UGE, CmpStmt::Predicate::ICMP_ULT}, // >= -> <
|
|
323
|
+
{CmpStmt::Predicate::ICMP_SGT, CmpStmt::Predicate::ICMP_SLE}, // > -> <=
|
|
324
|
+
{CmpStmt::Predicate::ICMP_SLT, CmpStmt::Predicate::ICMP_SGE}, // < -> >=
|
|
325
|
+
{CmpStmt::Predicate::ICMP_SGE, CmpStmt::Predicate::ICMP_SLT}, // >= -> <
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
Map<s32_t, s32_t> _switch_lhsrhs_predicate =
|
|
330
|
+
{
|
|
331
|
+
{CmpStmt::Predicate::FCMP_OEQ, CmpStmt::Predicate::FCMP_OEQ}, // == -> ==
|
|
332
|
+
{CmpStmt::Predicate::FCMP_UEQ, CmpStmt::Predicate::FCMP_UEQ}, // == -> ==
|
|
333
|
+
{CmpStmt::Predicate::FCMP_OGT, CmpStmt::Predicate::FCMP_OLT}, // > -> <
|
|
334
|
+
{CmpStmt::Predicate::FCMP_OGE, CmpStmt::Predicate::FCMP_OLE}, // >= -> <=
|
|
335
|
+
{CmpStmt::Predicate::FCMP_OLT, CmpStmt::Predicate::FCMP_OGT}, // < -> >
|
|
336
|
+
{CmpStmt::Predicate::FCMP_OLE, CmpStmt::Predicate::FCMP_OGE}, // <= -> >=
|
|
337
|
+
{CmpStmt::Predicate::FCMP_ONE, CmpStmt::Predicate::FCMP_ONE}, // != -> !=
|
|
338
|
+
{CmpStmt::Predicate::FCMP_UNE, CmpStmt::Predicate::FCMP_UNE}, // != -> !=
|
|
339
|
+
{CmpStmt::Predicate::ICMP_EQ, CmpStmt::Predicate::ICMP_EQ}, // == -> ==
|
|
340
|
+
{CmpStmt::Predicate::ICMP_NE, CmpStmt::Predicate::ICMP_NE}, // != -> !=
|
|
341
|
+
{CmpStmt::Predicate::ICMP_UGT, CmpStmt::Predicate::ICMP_ULT}, // > -> <
|
|
342
|
+
{CmpStmt::Predicate::ICMP_ULT, CmpStmt::Predicate::ICMP_UGT}, // < -> >
|
|
343
|
+
{CmpStmt::Predicate::ICMP_UGE, CmpStmt::Predicate::ICMP_ULE}, // >= -> <=
|
|
344
|
+
{CmpStmt::Predicate::ICMP_SGT, CmpStmt::Predicate::ICMP_SLT}, // > -> <
|
|
345
|
+
{CmpStmt::Predicate::ICMP_SLT, CmpStmt::Predicate::ICMP_SGT}, // < -> >
|
|
346
|
+
{CmpStmt::Predicate::ICMP_SGE, CmpStmt::Predicate::ICMP_SLE}, // >= -> <=
|
|
347
|
+
};
|
|
369
348
|
|
|
370
349
|
};
|
|
371
350
|
}
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
//
|
|
27
27
|
|
|
28
28
|
#include <AE/Svfexe/AEDetector.h>
|
|
29
|
+
#include <AE/Svfexe/AbsExtAPI.h>
|
|
29
30
|
#include <AE/Svfexe/AbstractInterpretation.h>
|
|
30
31
|
|
|
31
32
|
using namespace SVF;
|
|
@@ -101,6 +102,85 @@ void BufOverflowDetector::detect(AbstractState& as, const ICFGNode* node)
|
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
104
|
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @brief Handles stub functions within the ICFG node.
|
|
108
|
+
*
|
|
109
|
+
* This function is a placeholder for handling stub functions within the ICFG node.
|
|
110
|
+
*
|
|
111
|
+
* @param node Pointer to the ICFG node.
|
|
112
|
+
*/
|
|
113
|
+
void BufOverflowDetector::handleStubFunctions(const SVF::CallICFGNode* callNode)
|
|
114
|
+
{
|
|
115
|
+
// get function name
|
|
116
|
+
SVFIR* svfir = PAG::getPAG();
|
|
117
|
+
std::string funcName = callNode->getCalledFunction()->getName();
|
|
118
|
+
if (funcName == "SAFE_BUFACCESS")
|
|
119
|
+
{
|
|
120
|
+
// void SAFE_BUFACCESS(void* data, int size);
|
|
121
|
+
AbstractInterpretation::getAEInstance().checkpoints.erase(callNode);
|
|
122
|
+
if (callNode->arg_size() < 2)
|
|
123
|
+
return;
|
|
124
|
+
AbstractState& as =
|
|
125
|
+
AbstractInterpretation::getAEInstance().getAbsStateFromTrace(
|
|
126
|
+
callNode);
|
|
127
|
+
u32_t size_id = svfir->getValueNode(callNode->getArgument(1));
|
|
128
|
+
IntervalValue val = as[size_id].getInterval();
|
|
129
|
+
if (val.isBottom())
|
|
130
|
+
{
|
|
131
|
+
val = IntervalValue(0);
|
|
132
|
+
assert(false && "SAFE_BUFACCESS size is bottom");
|
|
133
|
+
}
|
|
134
|
+
const SVFVar* arg0Val =
|
|
135
|
+
AbstractInterpretation::getAEInstance().getUtils()->getSVFVar(
|
|
136
|
+
callNode->getArgument(0));
|
|
137
|
+
bool isSafe = canSafelyAccessMemory(as, arg0Val, val);
|
|
138
|
+
if (isSafe)
|
|
139
|
+
{
|
|
140
|
+
std::cout << "safe buffer access success: " << callNode->toString()
|
|
141
|
+
<< std::endl;
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
else
|
|
145
|
+
{
|
|
146
|
+
std::string err_msg = "this SAFE_BUFACCESS should be a safe access but detected buffer overflow. Pos: ";
|
|
147
|
+
err_msg += callNode->getSourceLoc();
|
|
148
|
+
std::cerr << err_msg << std::endl;
|
|
149
|
+
assert(false);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else if (funcName == "UNSAFE_BUFACCESS")
|
|
153
|
+
{
|
|
154
|
+
// handle other stub functions
|
|
155
|
+
//void UNSAFE_BUFACCESS(void* data, int size);
|
|
156
|
+
AbstractInterpretation::getAEInstance().checkpoints.erase(callNode);
|
|
157
|
+
if (callNode->arg_size() < 2) return;
|
|
158
|
+
AbstractState&as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode);
|
|
159
|
+
u32_t size_id = svfir->getValueNode(callNode->getArgument(1));
|
|
160
|
+
IntervalValue val = as[size_id].getInterval();
|
|
161
|
+
if (val.isBottom())
|
|
162
|
+
{
|
|
163
|
+
assert(false && "UNSAFE_BUFACCESS size is bottom");
|
|
164
|
+
}
|
|
165
|
+
const SVFVar* arg0Val =
|
|
166
|
+
AbstractInterpretation::getAEInstance().getUtils()->getSVFVar(
|
|
167
|
+
callNode->getArgument(0));
|
|
168
|
+
bool isSafe = canSafelyAccessMemory(as, arg0Val, val);
|
|
169
|
+
if (!isSafe)
|
|
170
|
+
{
|
|
171
|
+
std::cout << "detect buffer overflow success: " << callNode->toString() << std::endl;
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
else
|
|
175
|
+
{
|
|
176
|
+
std::string err_msg = "this UNSAFE_BUFACCESS should be a buffer overflow but not detected. Pos: ";
|
|
177
|
+
err_msg += callNode->getSourceLoc();
|
|
178
|
+
std::cerr << err_msg << std::endl;
|
|
179
|
+
assert(false);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
104
184
|
/**
|
|
105
185
|
* @brief Initializes external API buffer overflow check rules.
|
|
106
186
|
*
|
|
@@ -147,23 +227,23 @@ void BufOverflowDetector::detectExtAPI(AbstractState& as,
|
|
|
147
227
|
SVFIR* svfir = PAG::getPAG();
|
|
148
228
|
assert(call->getCalledFunction() && "SVFFunction* is nullptr");
|
|
149
229
|
|
|
150
|
-
|
|
230
|
+
AbsExtAPI::ExtAPIType extType = AbsExtAPI::UNCLASSIFIED;
|
|
151
231
|
|
|
152
232
|
// Determine the type of external memory API
|
|
153
233
|
for (const std::string &annotation : ExtAPI::getExtAPI()->getExtFuncAnnotations(call->getCalledFunction()))
|
|
154
234
|
{
|
|
155
235
|
if (annotation.find("MEMCPY") != std::string::npos)
|
|
156
|
-
extType =
|
|
236
|
+
extType = AbsExtAPI::MEMCPY;
|
|
157
237
|
if (annotation.find("MEMSET") != std::string::npos)
|
|
158
|
-
extType =
|
|
238
|
+
extType = AbsExtAPI::MEMSET;
|
|
159
239
|
if (annotation.find("STRCPY") != std::string::npos)
|
|
160
|
-
extType =
|
|
240
|
+
extType = AbsExtAPI::STRCPY;
|
|
161
241
|
if (annotation.find("STRCAT") != std::string::npos)
|
|
162
|
-
extType =
|
|
242
|
+
extType = AbsExtAPI::STRCAT;
|
|
163
243
|
}
|
|
164
244
|
|
|
165
245
|
// Apply buffer overflow checks based on the determined API type
|
|
166
|
-
if (extType ==
|
|
246
|
+
if (extType == AbsExtAPI::MEMCPY)
|
|
167
247
|
{
|
|
168
248
|
if (extAPIBufOverflowCheckRules.count(call->getCalledFunction()->getName()) == 0)
|
|
169
249
|
{
|
|
@@ -175,14 +255,15 @@ void BufOverflowDetector::detectExtAPI(AbstractState& as,
|
|
|
175
255
|
for (auto arg : args)
|
|
176
256
|
{
|
|
177
257
|
IntervalValue offset = as[svfir->getValueNode(call->getArgument(arg.second))].getInterval() - IntervalValue(1);
|
|
178
|
-
|
|
258
|
+
const SVFVar* argVar = AbstractInterpretation::getAEInstance().getUtils()->getSVFVar(call->getArgument(arg.first));
|
|
259
|
+
if (!canSafelyAccessMemory(as, argVar, offset))
|
|
179
260
|
{
|
|
180
261
|
AEException bug(call->toString());
|
|
181
262
|
addBugToReporter(bug, call);
|
|
182
263
|
}
|
|
183
264
|
}
|
|
184
265
|
}
|
|
185
|
-
else if (extType ==
|
|
266
|
+
else if (extType == AbsExtAPI::MEMSET)
|
|
186
267
|
{
|
|
187
268
|
if (extAPIBufOverflowCheckRules.count(call->getCalledFunction()->getName()) == 0)
|
|
188
269
|
{
|
|
@@ -194,14 +275,15 @@ void BufOverflowDetector::detectExtAPI(AbstractState& as,
|
|
|
194
275
|
for (auto arg : args)
|
|
195
276
|
{
|
|
196
277
|
IntervalValue offset = as[svfir->getValueNode(call->getArgument(arg.second))].getInterval() - IntervalValue(1);
|
|
197
|
-
|
|
278
|
+
const SVFVar* argVar = AbstractInterpretation::getAEInstance().getUtils()->getSVFVar(call->getArgument(arg.first));
|
|
279
|
+
if (!canSafelyAccessMemory(as, argVar, offset))
|
|
198
280
|
{
|
|
199
281
|
AEException bug(call->toString());
|
|
200
282
|
addBugToReporter(bug, call);
|
|
201
283
|
}
|
|
202
284
|
}
|
|
203
285
|
}
|
|
204
|
-
else if (extType ==
|
|
286
|
+
else if (extType == AbsExtAPI::STRCPY)
|
|
205
287
|
{
|
|
206
288
|
if (!detectStrcpy(as, call))
|
|
207
289
|
{
|
|
@@ -209,7 +291,7 @@ void BufOverflowDetector::detectExtAPI(AbstractState& as,
|
|
|
209
291
|
addBugToReporter(bug, call);
|
|
210
292
|
}
|
|
211
293
|
}
|
|
212
|
-
else if (extType ==
|
|
294
|
+
else if (extType == AbsExtAPI::STRCAT)
|
|
213
295
|
{
|
|
214
296
|
if (!detectStrcat(as, call))
|
|
215
297
|
{
|
|
@@ -319,9 +401,9 @@ void BufOverflowDetector::updateGepObjOffsetFromBase(SVF::AddressValue gepAddrs,
|
|
|
319
401
|
*/
|
|
320
402
|
bool BufOverflowDetector::detectStrcpy(AbstractState& as, const CallICFGNode *call)
|
|
321
403
|
{
|
|
322
|
-
const
|
|
323
|
-
const
|
|
324
|
-
IntervalValue strLen = AbstractInterpretation::getAEInstance().getStrlen(as, arg1Val);
|
|
404
|
+
const SVFVar* arg0Val = AbstractInterpretation::getAEInstance().getUtils()->getSVFVar(call->getArgument(0));
|
|
405
|
+
const SVFVar* arg1Val = AbstractInterpretation::getAEInstance().getUtils()->getSVFVar(call->getArgument(1));
|
|
406
|
+
IntervalValue strLen = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(as, arg1Val);
|
|
325
407
|
return canSafelyAccessMemory(as, arg0Val, strLen);
|
|
326
408
|
}
|
|
327
409
|
|
|
@@ -337,26 +419,24 @@ bool BufOverflowDetector::detectStrcpy(AbstractState& as, const CallICFGNode *ca
|
|
|
337
419
|
*/
|
|
338
420
|
bool BufOverflowDetector::detectStrcat(AbstractState& as, const CallICFGNode *call)
|
|
339
421
|
{
|
|
340
|
-
SVFIR* svfir = PAG::getPAG();
|
|
341
|
-
|
|
342
422
|
const std::vector<std::string> strcatGroup = {"__strcat_chk", "strcat", "__wcscat_chk", "wcscat"};
|
|
343
423
|
const std::vector<std::string> strncatGroup = {"__strncat_chk", "strncat", "__wcsncat_chk", "wcsncat"};
|
|
344
424
|
|
|
345
425
|
if (std::find(strcatGroup.begin(), strcatGroup.end(), call->getCalledFunction()->getName()) != strcatGroup.end())
|
|
346
426
|
{
|
|
347
|
-
const
|
|
348
|
-
const
|
|
349
|
-
IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getStrlen(as, arg0Val);
|
|
350
|
-
IntervalValue strLen1 = AbstractInterpretation::getAEInstance().getStrlen(as, arg1Val);
|
|
427
|
+
const SVFVar* arg0Val = AbstractInterpretation::getAEInstance().getUtils()->getSVFVar(call->getArgument(0));
|
|
428
|
+
const SVFVar* arg1Val = AbstractInterpretation::getAEInstance().getUtils()->getSVFVar(call->getArgument(1));
|
|
429
|
+
IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(as, arg0Val);
|
|
430
|
+
IntervalValue strLen1 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(as, arg1Val);
|
|
351
431
|
IntervalValue totalLen = strLen0 + strLen1;
|
|
352
432
|
return canSafelyAccessMemory(as, arg0Val, totalLen);
|
|
353
433
|
}
|
|
354
434
|
else if (std::find(strncatGroup.begin(), strncatGroup.end(), call->getCalledFunction()->getName()) != strncatGroup.end())
|
|
355
435
|
{
|
|
356
|
-
const
|
|
357
|
-
const
|
|
358
|
-
IntervalValue arg2Num = as[
|
|
359
|
-
IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getStrlen(as, arg0Val);
|
|
436
|
+
const SVFVar* arg0Val = AbstractInterpretation::getAEInstance().getUtils()->getSVFVar(call->getArgument(0));
|
|
437
|
+
const SVFVar* arg2Val = AbstractInterpretation::getAEInstance().getUtils()->getSVFVar(call->getArgument(2));
|
|
438
|
+
IntervalValue arg2Num = as[arg2Val->getId()].getInterval();
|
|
439
|
+
IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(as, arg0Val);
|
|
360
440
|
IntervalValue totalLen = strLen0 + arg2Num;
|
|
361
441
|
return canSafelyAccessMemory(as, arg0Val, totalLen);
|
|
362
442
|
}
|
|
@@ -374,14 +454,14 @@ bool BufOverflowDetector::detectStrcat(AbstractState& as, const CallICFGNode *ca
|
|
|
374
454
|
* does not exceed the allocated size of the buffer.
|
|
375
455
|
*
|
|
376
456
|
* @param as Reference to the abstract state.
|
|
377
|
-
* @param value Pointer to the SVF
|
|
457
|
+
* @param value Pointer to the SVF var.
|
|
378
458
|
* @param len The interval value representing the length of the memory access.
|
|
379
459
|
* @return True if the memory access is safe, false otherwise.
|
|
380
460
|
*/
|
|
381
|
-
bool BufOverflowDetector::canSafelyAccessMemory(AbstractState& as, const SVF::
|
|
461
|
+
bool BufOverflowDetector::canSafelyAccessMemory(AbstractState& as, const SVF::SVFVar* value, const SVF::IntervalValue& len)
|
|
382
462
|
{
|
|
383
463
|
SVFIR* svfir = PAG::getPAG();
|
|
384
|
-
NodeID value_id =
|
|
464
|
+
NodeID value_id = value->getId();
|
|
385
465
|
|
|
386
466
|
assert(as[value_id].isAddr());
|
|
387
467
|
for (const auto& addr : as[value_id].getAddrs())
|