Last active
December 3, 2021 16:17
-
-
Save fegge/e75f24eece6ce3843623f9cd4524d760 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @name Unhandled CustomError | |
* @description A CustomError is returned from this function but it is not handled by the calling code. | |
* @kind path-problem | |
* @problem.severity warning | |
* @precision medium | |
* @tags security | |
* @id tob/local-unhandled-custom-error | |
*/ | |
import cpp | |
import semmle.code.cpp.dataflow.TaintTracking | |
class IgnoredFile extends File { | |
IgnoredFile() { | |
this.getAbsolutePath().matches("%test%") | |
} | |
} | |
class CustomError extends FunctionCall { | |
CustomError() { | |
this.getUnderlyingType().getName() = "CustomErrorType" | |
} | |
// True if the return value is checked locally. | |
predicate isCheckedLocally() { | |
// The return value flows into the condition of an if-statement. | |
exists (IfStmt is | | |
TaintTracking::localTaint( | |
DataFlow::exprNode(this), | |
DataFlow::exprNode(is.getCondition().getAChild*()) | |
) | |
) or | |
// The return value flows into the condition of a while-statement. | |
exists (WhileStmt ws | | |
TaintTracking::localTaint( | |
DataFlow::exprNode(this), | |
DataFlow::exprNode(ws.getCondition().getAChild*()) | |
) | |
) or | |
// The return value flows into the condition of a switch-statement. | |
exists (SwitchStmt ss | | |
TaintTracking::localTaint( | |
DataFlow::exprNode(this), | |
DataFlow::exprNode(ss.getExpr().getAChild*()) | |
) | |
) | |
} | |
// The return value is returned from the enclosing function. | |
predicate isReturnValue() { | |
exists (ReturnStmt rs | | |
TaintTracking::localTaint( | |
DataFlow::exprNode(this), | |
DataFlow::exprNode(rs.getExpr()) | |
) | |
) | |
} | |
// The return value is passed as an argument to another function. | |
predicate isPassedToFunction() { | |
exists (FunctionCall fc | | |
TaintTracking::localTaint( | |
DataFlow::exprNode(this), | |
DataFlow::exprNode(fc.getAnArgument()) | |
) | |
) | |
} | |
// Test if the return value is assigned to a member variable. | |
predicate isAssignedToMemberVar() { | |
exists (MemberVariable mv, MemberFunction mf | | |
mf = this.getEnclosingFunction() and | |
mf.canAccessMember(mv, mf.getDeclaringType()) and | |
TaintTracking::localTaint( | |
DataFlow::exprNode(this), | |
DataFlow::exprNode(mv.getAnAccess()) | |
) | |
) | |
} | |
predicate isChecked() { | |
this.isReturnValue() or | |
this.isCheckedLocally() or | |
this.isPassedToFunction() or | |
this.isAssignedToMemberVar() | |
} | |
} | |
from | |
CustomError ce | |
where | |
not ce.isChecked() and | |
not ce.getFile() instanceof IgnoredFile | |
select | |
ce.getLocation(), | |
"Unhandled error code in ", ce.getEnclosingFunction().getName(), | |
"Error code returned by ", ce.getTarget().getName() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment