Static Value-Flow Analysis
Public Member Functions | Static Public Member Functions | Private Member Functions | Private Attributes | Friends | List of all members
SVF::BufOverflowDetector Class Reference

Detector for identifying buffer overflow issues. More...

#include <AEDetector.h>

Inheritance diagram for SVF::BufOverflowDetector:
SVF::AEDetector

Public Member Functions

 BufOverflowDetector ()
 Constructor initializes the detector kind to BUF_OVERFLOW and sets up external API buffer overflow rules. More...
 
 ~BufOverflowDetector ()=default
 Destructor. More...
 
void updateGepObjOffsetFromBase (AddressValue gepAddrs, AddressValue objAddrs, IntervalValue offset)
 Updates the offset of a GEP object from its base. More...
 
void detect (AbstractState &as, const ICFGNode *)
 Detect buffer overflow issues within a node. More...
 
void handleStubFunctions (const CallICFGNode *)
 Handles external API calls related to buffer overflow detection. More...
 
void addToGepObjOffsetFromBase (const GepObjVar *obj, const IntervalValue &offset)
 Adds an offset to a GEP object. More...
 
bool hasGepObjOffsetFromBase (const GepObjVar *obj) const
 Checks if a GEP object has an associated offset. More...
 
IntervalValue getGepObjOffsetFromBase (const GepObjVar *obj) const
 Retrieves the offset of a GEP object from its base. More...
 
IntervalValue getAccessOffset (AbstractState &as, NodeID objId, const GepStmt *gep)
 Retrieves the access offset for a given object and GEP statement. More...
 
void addBugToReporter (const AEException &e, const ICFGNode *node)
 Adds a bug to the reporter based on an exception. More...
 
void reportBug ()
 Reports all detected buffer overflow bugs. More...
 
void initExtAPIBufOverflowCheckRules ()
 Initializes external API buffer overflow check rules. More...
 
void detectExtAPI (AbstractState &as, const CallICFGNode *call)
 Handles external API calls related to buffer overflow detection. More...
 
bool canSafelyAccessMemory (AbstractState &as, const SVFVar *value, const IntervalValue &len)
 Checks if memory can be safely accessed. More...
 
- Public Member Functions inherited from SVF::AEDetector
 AEDetector ()
 Constructor initializes the detector kind to UNKNOWN. More...
 
virtual ~AEDetector ()=default
 Virtual destructor for safe polymorphic use. More...
 
DetectorKind getKind () const
 Get the kind of the detector. More...
 

Static Public Member Functions

static bool classof (const AEDetector *detector)
 Check if the detector is of the BUF_OVERFLOW kind. More...
 
- Static Public Member Functions inherited from SVF::AEDetector
static bool classof (const AEDetector *detector)
 Check if the detector is of the UNKNOWN kind. More...
 

Private Member Functions

bool detectStrcat (AbstractState &as, const CallICFGNode *call)
 Detects buffer overflow in 'strcat' function calls. More...
 
bool detectStrcpy (AbstractState &as, const CallICFGNode *call)
 Detects buffer overflow in 'strcpy' function calls. More...
 

Private Attributes

Map< const GepObjVar *, IntervalValuegepObjOffsetFromBase
 Maps GEP objects to their offsets from the base. More...
 
Map< std::string, std::vector< std::pair< u32_t, u32_t > > > extAPIBufOverflowCheckRules
 Rules for checking buffer overflows in external APIs. More...
 
Set< std::stringbugLoc
 Set of locations where bugs have been reported. More...
 
SVFBugReport recoder
 Recorder for abstract execution bugs. More...
 
Map< const ICFGNode *, std::stringnodeToBugInfo
 Maps ICFG nodes to bug information. More...
 

Friends

class AbstractInterpretation
 

Additional Inherited Members

- Public Types inherited from SVF::AEDetector
enum  DetectorKind { BUF_OVERFLOW , UNKNOWN }
 Enumerates the types of detectors available. More...
 
- Protected Attributes inherited from SVF::AEDetector
DetectorKind kind
 The kind of the detector. More...
 

Detailed Description

Detector for identifying buffer overflow issues.

Definition at line 133 of file AEDetector.h.

Constructor & Destructor Documentation

◆ BufOverflowDetector()

SVF::BufOverflowDetector::BufOverflowDetector ( )
inline

Constructor initializes the detector kind to BUF_OVERFLOW and sets up external API buffer overflow rules.

Definition at line 140 of file AEDetector.h.

141  {
142  kind = BUF_OVERFLOW;
144  }
@ BUF_OVERFLOW
Detector for buffer overflow issues.
Definition: AEDetector.h:47
DetectorKind kind
The kind of the detector.
Definition: AEDetector.h:99
void initExtAPIBufOverflowCheckRules()
Initializes external API buffer overflow check rules.
Definition: AEDetector.cpp:186

◆ ~BufOverflowDetector()

SVF::BufOverflowDetector::~BufOverflowDetector ( )
default

Destructor.

Member Function Documentation

◆ addBugToReporter()

void SVF::BufOverflowDetector::addBugToReporter ( const AEException e,
const ICFGNode node 
)
inline

Adds a bug to the reporter based on an exception.

Parameters
eThe exception that was thrown.
nodePointer to the ICFG node where the bug was detected.

Definition at line 232 of file AEDetector.h.

233  {
234 
235  GenericBug::EventStack eventStack;
236  SVFBugEvent sourceInstEvent(SVFBugEvent::EventType::SourceInst, node);
237  eventStack.push_back(sourceInstEvent); // Add the source instruction event to the event stack
238 
239  if (eventStack.empty())
240  {
241  return; // If the event stack is empty, return early
242  }
243 
244  std::string loc = eventStack.back().getEventLoc(); // Get the location of the last event in the stack
245 
246  // Check if the bug at this location has already been reported
247  if (bugLoc.find(loc) != bugLoc.end())
248  {
249  return; // If the bug location is already reported, return early
250  }
251  else
252  {
253  bugLoc.insert(loc); // Otherwise, mark this location as reported
254  }
255 
256  // Add the bug to the recorder with details from the event stack
257  recoder.addAbsExecBug(GenericBug::FULLBUFOVERFLOW, eventStack, 0, 0, 0, 0);
258  nodeToBugInfo[node] = e.what(); // Record the exception information for the node
259  }
const char *const string
Definition: cJSON.h:172
SVFBugReport recoder
Recorder for abstract execution bugs.
Definition: AEDetector.h:320
Set< std::string > bugLoc
Set of locations where bugs have been reported.
Definition: AEDetector.h:319
Map< const ICFGNode *, std::string > nodeToBugInfo
Maps ICFG nodes to bug information.
Definition: AEDetector.h:321
std::vector< SVFBugEvent > EventStack
Definition: SVFBugReport.h:83
void addAbsExecBug(GenericBug::BugType bugType, const GenericBug::EventStack &eventStack, s64_t allocLowerBound, s64_t allocUpperBound, s64_t accessLowerBound, s64_t accessUpperBound)
Definition: SVFBugReport.h:367

◆ addToGepObjOffsetFromBase()

void SVF::BufOverflowDetector::addToGepObjOffsetFromBase ( const GepObjVar obj,
const IntervalValue offset 
)
inline

Adds an offset to a GEP object.

Parameters
objPointer to the GEP object.
offsetThe interval value of the offset.

Definition at line 190 of file AEDetector.h.

191  {
193  }
buffer offset
Definition: cJSON.cpp:1113
Map< const GepObjVar *, IntervalValue > gepObjOffsetFromBase
Maps GEP objects to their offsets from the base.
Definition: AEDetector.h:317

◆ canSafelyAccessMemory()

bool BufOverflowDetector::canSafelyAccessMemory ( AbstractState as,
const SVFVar value,
const IntervalValue len 
)

Checks if memory can be safely accessed.

Checks if a memory access is safe given a specific buffer length.

Parameters
asReference to the abstract state.
valuePointer to the SVF var.
lenThe interval value representing the length of the memory access.
Returns
True if the memory access is safe, false otherwise.

This function ensures that a given memory access, starting at a specific value, does not exceed the allocated size of the buffer.

Parameters
asReference to the abstract state.
valuePointer to the SVF var.
lenThe interval value representing the length of the memory access.
Returns
True if the memory access is safe, false otherwise.

Definition at line 456 of file AEDetector.cpp.

457 {
458  SVFIR* svfir = PAG::getPAG();
459  NodeID value_id = value->getId();
460 
461  assert(as[value_id].isAddr());
462  for (const auto& addr : as[value_id].getAddrs())
463  {
464  NodeID objId = AbstractState::getInternalID(addr);
465  u32_t size = 0;
466 
467  // if the object is a constant size object, get the size directly
468  if (svfir->getBaseObj(objId)->isConstantByteSize())
469  {
470  size = svfir->getBaseObj(objId)->getByteSizeOfObj();
471  }
472  else
473  {
474  // if the object is not a constant size object, get the size from the addrStmt
475  const ICFGNode* addrNode = SVFUtil::cast<ICFGNode>(
476  svfir->getBaseObj(objId)->getGNode());
477  for (const SVFStmt* stmt2 : addrNode->getSVFStmts())
478  {
479  if (const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt2))
480  {
481  size = as.getAllocaInstByteSize(addrStmt);
482  }
483  }
484  }
485 
487  // if the object is a GepObjVar, get the offset from the base object
488  if (SVFUtil::isa<GepObjVar>(svfir->getGNode(objId)))
489  {
490  offset = getGepObjOffsetFromBase(SVFUtil::cast<GepObjVar>(svfir->getGNode(objId))) + len;
491  }
492  else
493  {
494  // if the object is a FIObjVar, get the offset directly
495  offset = len;
496  }
497  // if the offset is greater than the size, return false
498  if (offset.ub().getIntNumeral() >= size)
499  {
500  return false;
501  }
502  }
503  return true;
504 }
unsigned u32_t
Definition: CommandLine.h:18
u32_t getAllocaInstByteSize(const AddrStmt *addr)
static u32_t getInternalID(u32_t idx)
Return the internal index if idx is an address otherwise return the value of idx.
IntervalValue getGepObjOffsetFromBase(const GepObjVar *obj) const
Retrieves the offset of a GEP object from its base.
Definition: AEDetector.h:210
NodeType * getGNode(NodeID id) const
Get a node.
Definition: GenericGraph.h:653
const SVFStmtList & getSVFStmts() const
Definition: ICFGNode.h:117
const SVFBaseNode * getGNode() const
Get the reference value to this object.
u32_t getByteSizeOfObj() const
Get the byte size of this object.
bool isConstantByteSize() const
Check if byte size is a const value.
NodeID getId() const
Get ID.
Definition: GenericGraph.h:260
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition: SVFIR.h:115
const MemObj * getBaseObj(NodeID id) const
Definition: SVFIR.h:459
u32_t NodeID
Definition: GeneralType.h:55

◆ classof()

static bool SVF::BufOverflowDetector::classof ( const AEDetector detector)
inlinestatic

Check if the detector is of the BUF_OVERFLOW kind.

Parameters
detectorPointer to the detector.
Returns
True if the detector is of type BUF_OVERFLOW, false otherwise.

Definition at line 156 of file AEDetector.h.

157  {
158  return detector->getKind() == AEDetector::BUF_OVERFLOW;
159  }

◆ detect()

void BufOverflowDetector::detect ( AbstractState as,
const ICFGNode node 
)
virtual

Detect buffer overflow issues within a node.

Detects buffer overflow issues within a given ICFG node.

Parameters
asReference to the abstract state.
nodePointer to the ICFG node.

This function handles both non-call nodes, where it analyzes GEP (GetElementPtr) instructions for potential buffer overflows, and call nodes, where it checks for external API calls that may cause overflows.

Parameters
asReference to the abstract state.
nodePointer to the ICFG node.

Implements SVF::AEDetector.

Definition at line 44 of file AEDetector.cpp.

45 {
46  if (!SVFUtil::isa<CallICFGNode>(node))
47  {
48  // Handle non-call nodes by analyzing GEP instructions
49  for (const SVFStmt* stmt : node->getSVFStmts())
50  {
51  if (const GepStmt* gep = SVFUtil::dyn_cast<GepStmt>(stmt))
52  {
53  SVFIR* svfir = PAG::getPAG();
54  NodeID lhs = gep->getLHSVarID();
55  NodeID rhs = gep->getRHSVarID();
56 
57  // Update the GEP object offset from its base
58  updateGepObjOffsetFromBase(as[lhs].getAddrs(), as[rhs].getAddrs(), as.getByteOffset(gep));
59 
60  IntervalValue baseObjSize = IntervalValue::bottom();
61  AddressValue objAddrs = as[gep->getRHSVarID()].getAddrs();
62  for (const auto& addr : objAddrs)
63  {
65  u32_t size = 0;
66 
67  if (svfir->getBaseObj(objId)->isConstantByteSize())
68  {
69  size = svfir->getBaseObj(objId)->getByteSizeOfObj();
70  }
71  else
72  {
73  const ICFGNode* addrNode = SVFUtil::cast<ICFGNode>(
74  svfir->getBaseObj(objId)->getGNode());
75  for (const SVFStmt* stmt2 : addrNode->getSVFStmts())
76  {
77  if (const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt2))
78  {
79  size = as.getAllocaInstByteSize(addrStmt);
80  }
81  }
82  }
83 
84  // Calculate access offset and check for potential overflow
85  IntervalValue accessOffset = getAccessOffset(as, objId, gep);
86  if (accessOffset.ub().getIntNumeral() >= size)
87  {
88  AEException bug(stmt->toString());
89  addBugToReporter(bug, stmt->getICFGNode());
90  }
91  }
92  }
93  }
94  }
95  else
96  {
97  // Handle call nodes by checking for external API calls
98  const CallICFGNode* callNode = SVFUtil::cast<CallICFGNode>(node);
99  if (SVFUtil::isExtCall(callNode->getCalledFunction()))
100  {
101  detectExtAPI(as, callNode);
102  }
103  }
104 }
Exception class for handling errors in Abstract Execution.
Definition: AEDetector.h:107
IntervalValue getByteOffset(const GepStmt *gep)
s64_t getIntNumeral() const
Definition: NumericValue.h:703
IntervalValue getAccessOffset(AbstractState &as, NodeID objId, const GepStmt *gep)
Retrieves the access offset for a given object and GEP statement.
Definition: AEDetector.cpp:314
void updateGepObjOffsetFromBase(AddressValue gepAddrs, AddressValue objAddrs, IntervalValue offset)
Updates the offset of a GEP object from its base.
Definition: AEDetector.cpp:346
void detectExtAPI(AbstractState &as, const CallICFGNode *call)
Handles external API calls related to buffer overflow detection.
Definition: AEDetector.cpp:220
void addBugToReporter(const AEException &e, const ICFGNode *node)
Adds a bug to the reporter based on an exception.
Definition: AEDetector.h:232
const SVFFunction * getCalledFunction() const
Definition: ICFGNode.h:518
const BoundedInt & ub() const
Return the upper bound.
static IntervalValue bottom()
Create the bottom IntervalValue [+inf, -inf].
bool isExtCall(const SVFFunction *fun)
Definition: SVFUtil.h:278

◆ detectExtAPI()

void BufOverflowDetector::detectExtAPI ( AbstractState as,
const CallICFGNode call 
)

Handles external API calls related to buffer overflow detection.

Parameters
asReference to the abstract state.
callPointer to the call ICFG node.

This function checks the type of external memory API (e.g., memcpy, memset, strcpy, strcat) and applies the corresponding buffer overflow checks based on predefined rules.

Parameters
asReference to the abstract state.
callPointer to the call ICFG node.

Definition at line 220 of file AEDetector.cpp.

222 {
223  assert(call->getCalledFunction() && "SVFFunction* is nullptr");
224 
226 
227  // Determine the type of external memory API
228  for (const std::string &annotation : ExtAPI::getExtAPI()->getExtFuncAnnotations(call->getCalledFunction()))
229  {
230  if (annotation.find("MEMCPY") != std::string::npos)
231  extType = AbsExtAPI::MEMCPY;
232  if (annotation.find("MEMSET") != std::string::npos)
233  extType = AbsExtAPI::MEMSET;
234  if (annotation.find("STRCPY") != std::string::npos)
235  extType = AbsExtAPI::STRCPY;
236  if (annotation.find("STRCAT") != std::string::npos)
237  extType = AbsExtAPI::STRCAT;
238  }
239 
240  // Apply buffer overflow checks based on the determined API type
241  if (extType == AbsExtAPI::MEMCPY)
242  {
243  if (extAPIBufOverflowCheckRules.count(call->getCalledFunction()->getName()) == 0)
244  {
245  SVFUtil::errs() << "Warning: " << call->getCalledFunction()->getName() << " is not in the rules, please implement it\n";
246  return;
247  }
248  std::vector<std::pair<u32_t, u32_t>> args =
250  for (auto arg : args)
251  {
252  IntervalValue offset = as[call->getArgument(arg.second)->getId()].getInterval() - IntervalValue(1);
253  const SVFVar* argVar = call->getArgument(arg.first);
254  if (!canSafelyAccessMemory(as, argVar, offset))
255  {
256  AEException bug(call->toString());
257  addBugToReporter(bug, call);
258  }
259  }
260  }
261  else if (extType == AbsExtAPI::MEMSET)
262  {
263  if (extAPIBufOverflowCheckRules.count(call->getCalledFunction()->getName()) == 0)
264  {
265  SVFUtil::errs() << "Warning: " << call->getCalledFunction()->getName() << " is not in the rules, please implement it\n";
266  return;
267  }
268  std::vector<std::pair<u32_t, u32_t>> args =
270  for (auto arg : args)
271  {
272  IntervalValue offset = as[call->getArgument(arg.second)->getId()].getInterval() - IntervalValue(1);
273  const SVFVar* argVar = call->getArgument(arg.first);
274  if (!canSafelyAccessMemory(as, argVar, offset))
275  {
276  AEException bug(call->toString());
277  addBugToReporter(bug, call);
278  }
279  }
280  }
281  else if (extType == AbsExtAPI::STRCPY)
282  {
283  if (!detectStrcpy(as, call))
284  {
285  AEException bug(call->toString());
286  addBugToReporter(bug, call);
287  }
288  }
289  else if (extType == AbsExtAPI::STRCAT)
290  {
291  if (!detectStrcat(as, call))
292  {
293  AEException bug(call->toString());
294  addBugToReporter(bug, call);
295  }
296  }
297  else
298  {
299  // Handle other cases
300  }
301 }
ExtAPIType
Enumeration of external API types.
Definition: AbsExtAPI.h:52
Map< std::string, std::vector< std::pair< u32_t, u32_t > > > extAPIBufOverflowCheckRules
Rules for checking buffer overflows in external APIs.
Definition: AEDetector.h:318
bool detectStrcpy(AbstractState &as, const CallICFGNode *call)
Detects buffer overflow in 'strcpy' function calls.
Definition: AEDetector.cpp:397
bool detectStrcat(AbstractState &as, const CallICFGNode *call)
Detects buffer overflow in 'strcat' function calls.
Definition: AEDetector.cpp:415
bool canSafelyAccessMemory(AbstractState &as, const SVFVar *value, const IntervalValue &len)
Checks if memory can be safely accessed.
Definition: AEDetector.cpp:456
const std::string toString() const override
Definition: ICFG.cpp:131
const SVFVar * getArgument(u32_t ArgNo) const
Parameter operations.
Definition: ICFGNode.h:500
static ExtAPI * getExtAPI()
Definition: ExtAPI.cpp:42
const std::string & getName() const
Definition: SVFValue.h:243
std::ostream & errs()
Overwrite llvm::errs()
Definition: SVFUtil.h:56

◆ detectStrcat()

bool BufOverflowDetector::detectStrcat ( AbstractState as,
const CallICFGNode call 
)
private

Detects buffer overflow in 'strcat' function calls.

Parameters
asReference to the abstract state.
callPointer to the call ICFG node.
Returns
True if a buffer overflow is detected, false otherwise.

This function checks if the destination buffer can safely accommodate both the existing string and the concatenated string from the source.

Parameters
asReference to the abstract state.
callPointer to the call ICFG node.
Returns
True if the memory access is safe, false otherwise.

Definition at line 415 of file AEDetector.cpp.

416 {
417  const std::vector<std::string> strcatGroup = {"__strcat_chk", "strcat", "__wcscat_chk", "wcscat"};
418  const std::vector<std::string> strncatGroup = {"__strncat_chk", "strncat", "__wcsncat_chk", "wcsncat"};
419 
420  if (std::find(strcatGroup.begin(), strcatGroup.end(), call->getCalledFunction()->getName()) != strcatGroup.end())
421  {
422  const SVFVar* arg0Val = call->getArgument(0);
423  const SVFVar* arg1Val = call->getArgument(1);
426  IntervalValue totalLen = strLen0 + strLen1;
427  return canSafelyAccessMemory(as, arg0Val, totalLen);
428  }
429  else if (std::find(strncatGroup.begin(), strncatGroup.end(), call->getCalledFunction()->getName()) != strncatGroup.end())
430  {
431  const SVFVar* arg0Val = call->getArgument(0);
432  const SVFVar* arg2Val = call->getArgument(2);
433  IntervalValue arg2Num = as[arg2Val->getId()].getInterval();
435  IntervalValue totalLen = strLen0 + arg2Num;
436  return canSafelyAccessMemory(as, arg0Val, totalLen);
437  }
438  else
439  {
440  assert(false && "Unknown strcat function, please add it to strcatGroup or strncatGroup");
441  abort();
442  }
443 }
IntervalValue getStrlen(AbstractState &as, const SVF::SVFVar *strValue)
Calculates the length of a string.
Definition: AbsExtAPI.cpp:469
static AbstractInterpretation & getAEInstance()

◆ detectStrcpy()

bool BufOverflowDetector::detectStrcpy ( AbstractState as,
const CallICFGNode call 
)
private

Detects buffer overflow in 'strcpy' function calls.

Parameters
asReference to the abstract state.
callPointer to the call ICFG node.
Returns
True if a buffer overflow is detected, false otherwise.

This function checks if the destination buffer can safely accommodate the source string being copied, accounting for the null terminator.

Parameters
asReference to the abstract state.
callPointer to the call ICFG node.
Returns
True if the memory access is safe, false otherwise.

Definition at line 397 of file AEDetector.cpp.

398 {
399  const SVFVar* arg0Val = call->getArgument(0);
400  const SVFVar* arg1Val = call->getArgument(1);
402  return canSafelyAccessMemory(as, arg0Val, strLen);
403 }

◆ getAccessOffset()

IntervalValue BufOverflowDetector::getAccessOffset ( SVF::AbstractState as,
SVF::NodeID  objId,
const GepStmt gep 
)

Retrieves the access offset for a given object and GEP statement.

Parameters
asReference to the abstract state.
objIdThe ID of the object.
gepPointer to the GEP statement.
Returns
The interval value of the access offset.

This function calculates the access offset for a base object or a sub-object of an aggregate object (using GEP). If the object is a dummy object, it returns a top interval value.

Parameters
asReference to the abstract state.
objIdThe ID of the object.
gepPointer to the GEP statement.
Returns
The interval value of the access offset.

Definition at line 314 of file AEDetector.cpp.

315 {
316  SVFIR* svfir = PAG::getPAG();
317  auto obj = svfir->getGNode(objId);
318 
319  // if the object is a FIObjVar, return the byte offset directly
320  if (SVFUtil::isa<FIObjVar>(obj))
321  {
322  return as.getByteOffset(gep);
323  }
324  else if (SVFUtil::isa<GepObjVar>(obj))
325  {
326  // if the object is a GepObjVar, return the offset from the base object
327  return getGepObjOffsetFromBase(SVFUtil::cast<GepObjVar>(obj)) + as.getByteOffset(gep);
328  }
329  else
330  {
331  assert(SVFUtil::isa<DummyObjVar>(obj) && "Unknown object type");
332  return IntervalValue::top();
333  }
334 }
static IntervalValue top()
Create the IntervalValue [-inf, +inf].
Definition: IntervalValue.h:94

◆ getGepObjOffsetFromBase()

IntervalValue SVF::BufOverflowDetector::getGepObjOffsetFromBase ( const GepObjVar obj) const
inline

Retrieves the offset of a GEP object from its base.

Parameters
objPointer to the GEP object.
Returns
The interval value of the offset.

Definition at line 210 of file AEDetector.h.

211  {
212  if (hasGepObjOffsetFromBase(obj))
213  return gepObjOffsetFromBase.at(obj);
214  else
215  assert(false && "GepObjVar not found in gepObjOffsetFromBase");
216  }
bool hasGepObjOffsetFromBase(const GepObjVar *obj) const
Checks if a GEP object has an associated offset.
Definition: AEDetector.h:200

◆ handleStubFunctions()

void BufOverflowDetector::handleStubFunctions ( const CallICFGNode callNode)
virtual

Handles external API calls related to buffer overflow detection.

Handles stub functions within the ICFG node.

Parameters
callPointer to the call ICFG node.

This function is a placeholder for handling stub functions within the ICFG node.

Parameters
nodePointer to the ICFG node.

Implements SVF::AEDetector.

Definition at line 114 of file AEDetector.cpp.

115 {
116  // get function name
117  std::string funcName = callNode->getCalledFunction()->getName();
118  if (funcName == "SAFE_BUFACCESS")
119  {
120  // void SAFE_BUFACCESS(void* data, int size);
122  if (callNode->arg_size() < 2)
123  return;
124  AbstractState& as =
126  callNode);
127  u32_t size_id = callNode->getArgument(1)->getId();
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 = callNode->getArgument(0);
135  bool isSafe = canSafelyAccessMemory(as, arg0Val, val);
136  if (isSafe)
137  {
138  std::cout << "safe buffer access success: " << callNode->toString()
139  << std::endl;
140  return;
141  }
142  else
143  {
144  std::string err_msg = "this SAFE_BUFACCESS should be a safe access but detected buffer overflow. Pos: ";
145  err_msg += callNode->getSourceLoc();
146  std::cerr << err_msg << std::endl;
147  assert(false);
148  }
149  }
150  else if (funcName == "UNSAFE_BUFACCESS")
151  {
152  // handle other stub functions
153  //void UNSAFE_BUFACCESS(void* data, int size);
155  if (callNode->arg_size() < 2) return;
157  u32_t size_id = callNode->getArgument(1)->getId();
158  IntervalValue val = as[size_id].getInterval();
159  if (val.isBottom())
160  {
161  assert(false && "UNSAFE_BUFACCESS size is bottom");
162  }
163  const SVFVar* arg0Val = callNode->getArgument(0);
164  bool isSafe = canSafelyAccessMemory(as, arg0Val, val);
165  if (!isSafe)
166  {
167  std::cout << "detect buffer overflow success: " << callNode->toString() << std::endl;
168  return;
169  }
170  else
171  {
172  std::string err_msg = "this UNSAFE_BUFACCESS should be a buffer overflow but not detected. Pos: ";
173  err_msg += callNode->getSourceLoc();
174  std::cerr << err_msg << std::endl;
175  assert(false);
176  }
177  }
178 }
Set< const CallICFGNode * > checkpoints
AbstractState & getAbsStateFromTrace(const ICFGNode *node)
const std::string getSourceLoc() const override
Definition: ICFGNode.h:588
u32_t arg_size() const
Definition: ICFGNode.h:505
bool isBottom() const
Definition: IntervalValue.h:71

◆ hasGepObjOffsetFromBase()

bool SVF::BufOverflowDetector::hasGepObjOffsetFromBase ( const GepObjVar obj) const
inline

Checks if a GEP object has an associated offset.

Parameters
objPointer to the GEP object.
Returns
True if the GEP object has an offset, false otherwise.

Definition at line 200 of file AEDetector.h.

201  {
202  return gepObjOffsetFromBase.find(obj) != gepObjOffsetFromBase.end();
203  }

◆ initExtAPIBufOverflowCheckRules()

void BufOverflowDetector::initExtAPIBufOverflowCheckRules ( )

Initializes external API buffer overflow check rules.

This function sets up rules for various memory-related functions like memcpy, memset, etc., defining which arguments should be checked for buffer overflows.

Definition at line 186 of file AEDetector.cpp.

187 {
188  extAPIBufOverflowCheckRules["llvm_memcpy_p0i8_p0i8_i64"] = {{0, 2}, {1, 2}};
189  extAPIBufOverflowCheckRules["llvm_memcpy_p0_p0_i64"] = {{0, 2}, {1, 2}};
190  extAPIBufOverflowCheckRules["llvm_memcpy_p0i8_p0i8_i32"] = {{0, 2}, {1, 2}};
191  extAPIBufOverflowCheckRules["llvm_memcpy"] = {{0, 2}, {1, 2}};
192  extAPIBufOverflowCheckRules["llvm_memmove"] = {{0, 2}, {1, 2}};
193  extAPIBufOverflowCheckRules["llvm_memmove_p0i8_p0i8_i64"] = {{0, 2}, {1, 2}};
194  extAPIBufOverflowCheckRules["llvm_memmove_p0_p0_i64"] = {{0, 2}, {1, 2}};
195  extAPIBufOverflowCheckRules["llvm_memmove_p0i8_p0i8_i32"] = {{0, 2}, {1, 2}};
196  extAPIBufOverflowCheckRules["__memcpy_chk"] = {{0, 2}, {1, 2}};
197  extAPIBufOverflowCheckRules["memmove"] = {{0, 2}, {1, 2}};
198  extAPIBufOverflowCheckRules["bcopy"] = {{0, 2}, {1, 2}};
199  extAPIBufOverflowCheckRules["memccpy"] = {{0, 3}, {1, 3}};
200  extAPIBufOverflowCheckRules["__memmove_chk"] = {{0, 2}, {1, 2}};
201  extAPIBufOverflowCheckRules["llvm_memset"] = {{0, 2}};
202  extAPIBufOverflowCheckRules["llvm_memset_p0i8_i32"] = {{0, 2}};
203  extAPIBufOverflowCheckRules["llvm_memset_p0i8_i64"] = {{0, 2}};
204  extAPIBufOverflowCheckRules["llvm_memset_p0_i64"] = {{0, 2}};
205  extAPIBufOverflowCheckRules["__memset_chk"] = {{0, 2}};
206  extAPIBufOverflowCheckRules["wmemset"] = {{0, 2}};
207  extAPIBufOverflowCheckRules["strncpy"] = {{0, 2}, {1, 2}};
208  extAPIBufOverflowCheckRules["iconv"] = {{1, 2}, {3, 4}};
209 }

◆ reportBug()

void SVF::BufOverflowDetector::reportBug ( )
inlinevirtual

Reports all detected buffer overflow bugs.

Implements SVF::AEDetector.

Definition at line 264 of file AEDetector.h.

265  {
266  if (!nodeToBugInfo.empty())
267  {
268  std::cerr << "######################Buffer Overflow (" + std::to_string(nodeToBugInfo.size())
269  + " found)######################\n";
270  std::cerr << "---------------------------------------------\n";
271  for (const auto& it : nodeToBugInfo)
272  {
273  std::cerr << it.second << "\n---------------------------------------------\n";
274  }
275  }
276  }

◆ updateGepObjOffsetFromBase()

void BufOverflowDetector::updateGepObjOffsetFromBase ( SVF::AddressValue  gepAddrs,
SVF::AddressValue  objAddrs,
SVF::IntervalValue  offset 
)

Updates the offset of a GEP object from its base.

Parameters
gepAddrsAddress value for GEP.
objAddrsAddress value for the object.
offsetThe interval value of the offset.

This function calculates and stores the offset of a GEP object from its base object using the addresses and offsets provided.

Parameters
gepAddrsThe addresses of the GEP objects.
objAddrsThe addresses of the base objects.
offsetThe interval value of the offset.

Definition at line 346 of file AEDetector.cpp.

347 {
348  SVFIR* svfir = PAG::getPAG();
349 
350  for (const auto& objAddr : objAddrs)
351  {
352  NodeID objId = AbstractState::getInternalID(objAddr);
353  auto obj = svfir->getGNode(objId);
354  // if the object is a FIObjVar, add the offset directly
355  if (SVFUtil::isa<FIObjVar>(obj))
356  {
357  for (const auto& gepAddr : gepAddrs)
358  {
359  NodeID gepObj = AbstractState::getInternalID(gepAddr);
360  const GepObjVar* gepObjVar = SVFUtil::cast<GepObjVar>(svfir->getGNode(gepObj));
361  addToGepObjOffsetFromBase(gepObjVar, offset);
362  }
363  }
364  else if (SVFUtil::isa<GepObjVar>(obj))
365  {
366  // if the object is a GepObjVar, add the offset from the base object
367  const GepObjVar* objVar = SVFUtil::cast<GepObjVar>(obj);
368  for (const auto& gepAddr : gepAddrs)
369  {
370  NodeID gepObj = AbstractState::getInternalID(gepAddr);
371  const GepObjVar* gepObjVar = SVFUtil::cast<GepObjVar>(svfir->getGNode(gepObj));
372  if (hasGepObjOffsetFromBase(objVar))
373  {
374  IntervalValue objOffsetFromBase = getGepObjOffsetFromBase(objVar);
375  if (!hasGepObjOffsetFromBase(gepObjVar))
376  addToGepObjOffsetFromBase(gepObjVar, objOffsetFromBase + offset);
377  }
378  else
379  {
380  assert(false && "GEP RHS object has no offset from base");
381  }
382  }
383  }
384  }
385 }
void addToGepObjOffsetFromBase(const GepObjVar *obj, const IntervalValue &offset)
Adds an offset to a GEP object.
Definition: AEDetector.h:190

Friends And Related Function Documentation

◆ AbstractInterpretation

friend class AbstractInterpretation
friend

Definition at line 135 of file AEDetector.h.

Member Data Documentation

◆ bugLoc

Set<std::string> SVF::BufOverflowDetector::bugLoc
private

Set of locations where bugs have been reported.

Definition at line 319 of file AEDetector.h.

◆ extAPIBufOverflowCheckRules

Map<std::string, std::vector<std::pair<u32_t, u32_t> > > SVF::BufOverflowDetector::extAPIBufOverflowCheckRules
private

Rules for checking buffer overflows in external APIs.

Definition at line 318 of file AEDetector.h.

◆ gepObjOffsetFromBase

Map<const GepObjVar*, IntervalValue> SVF::BufOverflowDetector::gepObjOffsetFromBase
private

Maps GEP objects to their offsets from the base.

Definition at line 317 of file AEDetector.h.

◆ nodeToBugInfo

Map<const ICFGNode*, std::string> SVF::BufOverflowDetector::nodeToBugInfo
private

Maps ICFG nodes to bug information.

Definition at line 321 of file AEDetector.h.

◆ recoder

SVFBugReport SVF::BufOverflowDetector::recoder
private

Recorder for abstract execution bugs.

Definition at line 320 of file AEDetector.h.


The documentation for this class was generated from the following files: