mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
CPP: Autoformat 'Critical'.
This commit is contained in:
@@ -26,9 +26,9 @@ predicate choice(LocalScopeVariable v, Stmt branch, string value) {
|
||||
exists(AnalysedExpr e |
|
||||
testAndBranch(e, branch) and
|
||||
(
|
||||
(e.getNullSuccessor(v) = branch and value = "null")
|
||||
e.getNullSuccessor(v) = branch and value = "null"
|
||||
or
|
||||
(e.getNonNullSuccessor(v) = branch and value = "non-null")
|
||||
e.getNonNullSuccessor(v) = branch and value = "non-null"
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -60,9 +60,9 @@ where
|
||||
exists(cond.getNullSuccessor(v)) and
|
||||
not addressLeak(v, branch.getChildStmt*()) and
|
||||
(
|
||||
(cond.isNullCheck(v) and test = "null")
|
||||
cond.isNullCheck(v) and test = "null"
|
||||
or
|
||||
(cond.isValidCheck(v) and test = "non-null")
|
||||
cond.isValidCheck(v) and test = "non-null"
|
||||
) and
|
||||
(if context = test then testresult = "succeed" else testresult = "fail")
|
||||
select cond,
|
||||
|
||||
@@ -7,28 +7,30 @@
|
||||
* @tags maintainability
|
||||
* external/cwe/cwe-561
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
predicate limitedScope(Function f)
|
||||
{
|
||||
(f.isStatic() and not (f instanceof MemberFunction))
|
||||
predicate limitedScope(Function f) {
|
||||
f.isStatic() and not f instanceof MemberFunction
|
||||
or
|
||||
f.(MemberFunction).isPrivate()
|
||||
}
|
||||
|
||||
predicate uncalled(Function f)
|
||||
{
|
||||
limitedScope(f)
|
||||
and not exists(Function g |
|
||||
g = f or g = f.(VirtualFunction).getAnOverriddenFunction+() |
|
||||
exists(g.getACallToThisFunction()) or
|
||||
exists(FunctionAccess fa | fa.getTarget() = g))
|
||||
predicate uncalled(Function f) {
|
||||
limitedScope(f) and
|
||||
not exists(Function g | g = f or g = f.(VirtualFunction).getAnOverriddenFunction+() |
|
||||
exists(g.getACallToThisFunction()) or
|
||||
exists(FunctionAccess fa | fa.getTarget() = g)
|
||||
)
|
||||
}
|
||||
|
||||
from Function f
|
||||
where uncalled(f)
|
||||
and forall(Function instance | f.(TemplateFunction).getAnInstantiation() = instance | uncalled(instance))
|
||||
where
|
||||
uncalled(f) and
|
||||
forall(Function instance | f.(TemplateFunction).getAnInstantiation() = instance |
|
||||
uncalled(instance)
|
||||
) and
|
||||
// tweaks for good results:
|
||||
and exists(f.getBlock())
|
||||
and not(f instanceof Constructor or f instanceof Destructor or f.hasName("operator="))
|
||||
exists(f.getBlock()) and
|
||||
not (f instanceof Constructor or f instanceof Destructor or f.hasName("operator="))
|
||||
select f, "Dead Code: this function is never called."
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @name Dead code due to goto or break statement
|
||||
* @description A goto or break statement is followed by unreachable code.
|
||||
* @description A goto or break statement is followed by unreachable code.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision high
|
||||
@@ -21,16 +21,17 @@ Stmt getNextRealStmt(Block b, int i) {
|
||||
}
|
||||
|
||||
from JumpStmt js, Block b, int i, Stmt s
|
||||
where b.getStmt(i) = js
|
||||
and s = getNextRealStmt(b, i)
|
||||
where
|
||||
b.getStmt(i) = js and
|
||||
s = getNextRealStmt(b, i) and
|
||||
// the next statement isn't jumped to
|
||||
and not s instanceof LabelStmt
|
||||
and not s instanceof SwitchCase
|
||||
not s instanceof LabelStmt and
|
||||
not s instanceof SwitchCase and
|
||||
// the next statement isn't breaking out of a switch
|
||||
and not s.(BreakStmt).getBreakable() instanceof SwitchStmt
|
||||
not s.(BreakStmt).getBreakable() instanceof SwitchStmt and
|
||||
// the next statement isn't a loop that can be jumped into
|
||||
and not exists (LabelStmt ls | s.(Loop).getStmt().getAChild*() = ls)
|
||||
and not exists (SwitchCase sc | s.(Loop).getStmt().getAChild*() = sc)
|
||||
not exists(LabelStmt ls | s.(Loop).getStmt().getAChild*() = ls) and
|
||||
not exists(SwitchCase sc | s.(Loop).getStmt().getAChild*() = sc) and
|
||||
// no preprocessor logic applies
|
||||
and not functionContainsPreprocCode(js.getEnclosingFunction())
|
||||
not functionContainsPreprocCode(js.getEnclosingFunction())
|
||||
select js, "This statement makes $@ unreachable.", s, s.toString()
|
||||
|
||||
@@ -8,54 +8,53 @@
|
||||
* security
|
||||
* external/cwe/cwe-775
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.pointsto.PointsTo
|
||||
import Negativity
|
||||
|
||||
predicate closeCall(FunctionCall fc, Variable v)
|
||||
{
|
||||
(fc.getTarget().hasQualifiedName("close") and v.getAnAccess() = fc.getArgument(0))
|
||||
predicate closeCall(FunctionCall fc, Variable v) {
|
||||
fc.getTarget().hasQualifiedName("close") and v.getAnAccess() = fc.getArgument(0)
|
||||
or
|
||||
exists(FunctionCall midcall, Function mid, int arg |
|
||||
fc.getArgument(arg) = v.getAnAccess() and
|
||||
fc.getTarget() = mid and
|
||||
midcall.getEnclosingFunction() = mid and
|
||||
closeCall(midcall, mid.getParameter(arg)))
|
||||
closeCall(midcall, mid.getParameter(arg))
|
||||
)
|
||||
}
|
||||
|
||||
predicate openDefinition(LocalScopeVariable v, ControlFlowNode def)
|
||||
{
|
||||
exists(Expr expr |
|
||||
exprDefinition(v, def, expr) and allocateDescriptorCall(expr))
|
||||
predicate openDefinition(LocalScopeVariable v, ControlFlowNode def) {
|
||||
exists(Expr expr | exprDefinition(v, def, expr) and allocateDescriptorCall(expr))
|
||||
}
|
||||
|
||||
predicate openReaches(ControlFlowNode def, ControlFlowNode node)
|
||||
{
|
||||
exists(LocalScopeVariable v |
|
||||
openDefinition(v, def) and node = def.getASuccessor())
|
||||
predicate openReaches(ControlFlowNode def, ControlFlowNode node) {
|
||||
exists(LocalScopeVariable v | openDefinition(v, def) and node = def.getASuccessor())
|
||||
or
|
||||
exists(LocalScopeVariable v, ControlFlowNode mid |
|
||||
openDefinition(v, def) and
|
||||
openReaches(def, mid) and
|
||||
not(errorSuccessor(v, mid)) and
|
||||
not(closeCall(mid, v)) and
|
||||
not(assignedToFieldOrGlobal(v, mid)) and
|
||||
node = mid.getASuccessor())
|
||||
not errorSuccessor(v, mid) and
|
||||
not closeCall(mid, v) and
|
||||
not assignedToFieldOrGlobal(v, mid) and
|
||||
node = mid.getASuccessor()
|
||||
)
|
||||
}
|
||||
|
||||
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Assignment assign)
|
||||
{
|
||||
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Assignment assign) {
|
||||
exists(Variable external |
|
||||
assign.getRValue() = v.getAnAccess() and
|
||||
assign.getLValue().(VariableAccess).getTarget() = external and
|
||||
(external instanceof Field or external instanceof GlobalVariable))
|
||||
(external instanceof Field or external instanceof GlobalVariable)
|
||||
)
|
||||
}
|
||||
|
||||
from LocalScopeVariable v, ControlFlowNode def, ReturnStmt ret
|
||||
where openDefinition(v, def)
|
||||
and openReaches(def, ret)
|
||||
and checkedSuccess(v, ret)
|
||||
and not(ret.getExpr().getAChild*() = v.getAnAccess())
|
||||
and exists(ReturnStmt other | other.getExpr() = v.getAnAccess())
|
||||
where
|
||||
openDefinition(v, def) and
|
||||
openReaches(def, ret) and
|
||||
checkedSuccess(v, ret) and
|
||||
not ret.getExpr().getAChild*() = v.getAnAccess() and
|
||||
exists(ReturnStmt other | other.getExpr() = v.getAnAccess())
|
||||
select ret,
|
||||
"Descriptor assigned to '" + v.getName().toString() + "' (line " +
|
||||
def.getLocation().getStartLine().toString() + ") may not be closed."
|
||||
def.getLocation().getStartLine().toString() + ") may not be closed."
|
||||
|
||||
@@ -8,22 +8,24 @@
|
||||
* security
|
||||
* external/cwe/cwe-775
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.pointsto.PointsTo
|
||||
|
||||
predicate closed(Expr e)
|
||||
{
|
||||
predicate closed(Expr e) {
|
||||
exists(FunctionCall fc |
|
||||
fc.getTarget().hasQualifiedName("close") and
|
||||
fc.getArgument(0) = e)
|
||||
fc.getArgument(0) = e
|
||||
)
|
||||
}
|
||||
|
||||
class ClosedExpr extends PointsToExpr
|
||||
{
|
||||
class ClosedExpr extends PointsToExpr {
|
||||
ClosedExpr() { closed(this) }
|
||||
|
||||
override predicate interesting() { closed(this) }
|
||||
}
|
||||
|
||||
from Expr alloc
|
||||
where allocateDescriptorCall(alloc)
|
||||
and not exists(ClosedExpr closed | closed.pointsTo() = alloc)
|
||||
where
|
||||
allocateDescriptorCall(alloc) and
|
||||
not exists(ClosedExpr closed | closed.pointsTo() = alloc)
|
||||
select alloc, "This file descriptor is never closed"
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import semmle.code.cpp.pointsto.PointsTo
|
||||
|
||||
predicate closed(Expr e) {
|
||||
fcloseCall(_, e) or
|
||||
exists(ExprCall c |
|
||||
// cautiously assume that any ExprCall could be a call to fclose.
|
||||
c.getAnArgument() = e
|
||||
)
|
||||
fcloseCall(_, e) or
|
||||
exists(ExprCall c |
|
||||
// cautiously assume that any ExprCall could be a call to fclose.
|
||||
c.getAnArgument() = e
|
||||
)
|
||||
}
|
||||
|
||||
class ClosedExpr extends PointsToExpr {
|
||||
ClosedExpr() { closed(this) }
|
||||
override predicate interesting() { closed(this) }
|
||||
ClosedExpr() { closed(this) }
|
||||
|
||||
override predicate interesting() { closed(this) }
|
||||
}
|
||||
|
||||
predicate fopenCallMayBeClosed(FunctionCall fc) {
|
||||
fopenCall(fc) and anythingPointsTo(fc)
|
||||
}
|
||||
predicate fopenCallMayBeClosed(FunctionCall fc) { fopenCall(fc) and anythingPointsTo(fc) }
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* security
|
||||
* external/cwe/cwe-775
|
||||
*/
|
||||
|
||||
import FileClosed
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
|
||||
@@ -15,8 +16,7 @@ import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
* Extend the NullValue class used by Nullness.qll to include simple -1 as a 'null' value
|
||||
* (for example 'open' returns -1 if there was an error)
|
||||
*/
|
||||
class MinusOne extends NullValue
|
||||
{
|
||||
class MinusOne extends NullValue {
|
||||
MinusOne() { this.(UnaryMinusExpr).getOperand().(Literal).getValue() = "1" }
|
||||
}
|
||||
|
||||
@@ -24,29 +24,27 @@ class MinusOne extends NullValue
|
||||
* 'call' is either a direct call to f, or a possible call to f
|
||||
* via a function pointer.
|
||||
*/
|
||||
predicate mayCallFunction(Expr call, Function f)
|
||||
{
|
||||
predicate mayCallFunction(Expr call, Function f) {
|
||||
call.(FunctionCall).getTarget() = f or
|
||||
call.(VariableCall).getVariable().getAnAssignedValue().getAChild*().(FunctionAccess).getTarget() = f
|
||||
call.(VariableCall).getVariable().getAnAssignedValue().getAChild*().(FunctionAccess).getTarget() =
|
||||
f
|
||||
}
|
||||
|
||||
predicate fopenCallOrIndirect(Expr e)
|
||||
{
|
||||
(
|
||||
// direct fopen call
|
||||
fopenCall(e) and
|
||||
|
||||
// We are only interested in fopen calls that are
|
||||
// actually closed somehow, as FileNeverClosed
|
||||
// will catch those that aren't.
|
||||
fopenCallMayBeClosed(e)
|
||||
) or exists(ReturnStmt rtn |
|
||||
predicate fopenCallOrIndirect(Expr e) {
|
||||
// direct fopen call
|
||||
fopenCall(e) and
|
||||
// We are only interested in fopen calls that are
|
||||
// actually closed somehow, as FileNeverClosed
|
||||
// will catch those that aren't.
|
||||
fopenCallMayBeClosed(e)
|
||||
or
|
||||
exists(ReturnStmt rtn |
|
||||
// indirect fopen call
|
||||
mayCallFunction(e, rtn.getEnclosingFunction()) and
|
||||
(
|
||||
// return fopen
|
||||
fopenCallOrIndirect(rtn.getExpr()) or
|
||||
|
||||
fopenCallOrIndirect(rtn.getExpr())
|
||||
or
|
||||
// return variable assigned with fopen
|
||||
exists(Variable v |
|
||||
v = rtn.getExpr().(VariableAccess).getTarget() and
|
||||
@@ -57,8 +55,7 @@ predicate fopenCallOrIndirect(Expr e)
|
||||
)
|
||||
}
|
||||
|
||||
predicate fcloseCallOrIndirect(FunctionCall fc, Variable v)
|
||||
{
|
||||
predicate fcloseCallOrIndirect(FunctionCall fc, Variable v) {
|
||||
// direct fclose call
|
||||
fcloseCall(fc, v.getAnAccess())
|
||||
or
|
||||
@@ -71,11 +68,8 @@ predicate fcloseCallOrIndirect(FunctionCall fc, Variable v)
|
||||
)
|
||||
}
|
||||
|
||||
predicate fopenDefinition(LocalScopeVariable v, ControlFlowNode def)
|
||||
{
|
||||
exists(Expr expr |
|
||||
exprDefinition(v, def, expr) and fopenCallOrIndirect(expr)
|
||||
)
|
||||
predicate fopenDefinition(LocalScopeVariable v, ControlFlowNode def) {
|
||||
exists(Expr expr | exprDefinition(v, def, expr) and fopenCallOrIndirect(expr))
|
||||
}
|
||||
|
||||
class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassignment {
|
||||
@@ -86,11 +80,10 @@ class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassi
|
||||
}
|
||||
|
||||
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
|
||||
// node may be used in fopenReaches
|
||||
// node may be used in fopenReaches
|
||||
exists(node.(AnalysedExpr).getNullSuccessor(v)) or
|
||||
fcloseCallOrIndirect(node, v) or
|
||||
assignedToFieldOrGlobal(v, node) or
|
||||
|
||||
// node may be used directly in query
|
||||
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
|
||||
}
|
||||
@@ -103,17 +96,14 @@ class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassi
|
||||
/**
|
||||
* The value from fopen at `def` is still held in Variable `v` upon entering `node`.
|
||||
*/
|
||||
predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node)
|
||||
{
|
||||
predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) {
|
||||
exists(FOpenVariableReachability r |
|
||||
// reachability
|
||||
r.reachesTo(def, _, node, v) or
|
||||
|
||||
r.reachesTo(def, _, node, v)
|
||||
or
|
||||
// accept def node itself
|
||||
(
|
||||
r.isSource(def, v) and
|
||||
node = def
|
||||
)
|
||||
r.isSource(def, v) and
|
||||
node = def
|
||||
)
|
||||
}
|
||||
|
||||
@@ -128,10 +118,11 @@ class FOpenReachability extends LocalScopeVariableReachabilityExt {
|
||||
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v) {
|
||||
override predicate isBarrier(
|
||||
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
|
||||
) {
|
||||
isSource(source, v) and
|
||||
next = node.getASuccessor() and
|
||||
|
||||
// the file (stored in any variable `v0`) opened at `source` is closed or
|
||||
// assigned to a global at node, or NULL checked on the edge node -> next.
|
||||
exists(LocalScopeVariable v0 | fopenVariableReaches(v0, source, node) |
|
||||
@@ -147,30 +138,26 @@ class FOpenReachability extends LocalScopeVariableReachabilityExt {
|
||||
* or potentially leaked globally upon reaching `node` (regardless of what variable
|
||||
* it's still held in, if any).
|
||||
*/
|
||||
predicate fopenReaches(ControlFlowNode def, ControlFlowNode node)
|
||||
{
|
||||
exists(FOpenReachability r |
|
||||
r.reaches(def, _, node)
|
||||
)
|
||||
predicate fopenReaches(ControlFlowNode def, ControlFlowNode node) {
|
||||
exists(FOpenReachability r | r.reaches(def, _, node))
|
||||
}
|
||||
|
||||
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e)
|
||||
{
|
||||
(
|
||||
// assigned to anything except a LocalScopeVariable
|
||||
// (typically a field or global, but for example also *ptr = v)
|
||||
e.(Assignment).getRValue() = v.getAnAccess() and
|
||||
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
|
||||
) or exists(Expr midExpr, Function mid, int arg |
|
||||
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
|
||||
// assigned to anything except a LocalScopeVariable
|
||||
// (typically a field or global, but for example also *ptr = v)
|
||||
e.(Assignment).getRValue() = v.getAnAccess() and
|
||||
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
|
||||
or
|
||||
exists(Expr midExpr, Function mid, int arg |
|
||||
// indirect assignment
|
||||
e.(FunctionCall).getArgument(arg) = v.getAnAccess() and
|
||||
mayCallFunction(e, mid) and
|
||||
midExpr.getEnclosingFunction() = mid and
|
||||
assignedToFieldOrGlobal(mid.getParameter(arg), midExpr)
|
||||
) or (
|
||||
// assigned to a field via constructor field initializer
|
||||
e.(ConstructorFieldInit).getExpr() = v.getAnAccess()
|
||||
)
|
||||
or
|
||||
// assigned to a field via constructor field initializer
|
||||
e.(ConstructorFieldInit).getExpr() = v.getAnAccess()
|
||||
}
|
||||
|
||||
from ControlFlowNode def, ReturnStmt ret
|
||||
@@ -180,6 +167,4 @@ where
|
||||
fopenVariableReaches(v, def, ret) and
|
||||
ret.getAChild*() = v.getAnAccess()
|
||||
)
|
||||
select
|
||||
def, "The file opened here may not be closed at $@.",
|
||||
ret, "this exit point"
|
||||
select def, "The file opened here may not be closed at $@.", ret, "this exit point"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* security
|
||||
* external/cwe/cwe-775
|
||||
*/
|
||||
|
||||
import FileClosed
|
||||
|
||||
from Expr alloc
|
||||
|
||||
@@ -8,103 +8,99 @@
|
||||
* security
|
||||
* external/cwe/cwe-457
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.pointsto.CallGraph
|
||||
|
||||
predicate initFunc(GlobalVariable v, Function f)
|
||||
{
|
||||
predicate initFunc(GlobalVariable v, Function f) {
|
||||
exists(VariableAccess access |
|
||||
v.getAnAccess() = access and
|
||||
access.isUsedAsLValue() and
|
||||
access.getEnclosingFunction() = f)
|
||||
access.getEnclosingFunction() = f
|
||||
)
|
||||
}
|
||||
|
||||
predicate useFunc(GlobalVariable v, Function f)
|
||||
{
|
||||
predicate useFunc(GlobalVariable v, Function f) {
|
||||
exists(VariableAccess access |
|
||||
v.getAnAccess() = access and
|
||||
access.isRValue() and
|
||||
access.getEnclosingFunction() = f)
|
||||
and
|
||||
access.getEnclosingFunction() = f
|
||||
) and
|
||||
not initFunc(v, f)
|
||||
}
|
||||
|
||||
predicate uninitialisedBefore(GlobalVariable v, Function f)
|
||||
{
|
||||
predicate uninitialisedBefore(GlobalVariable v, Function f) {
|
||||
f.hasQualifiedName("main")
|
||||
or
|
||||
exists(Call call, Function g |
|
||||
uninitialisedBefore(v, g) and
|
||||
call.getEnclosingFunction() = g and
|
||||
(not functionInitialises(f, v) or locallyUninitialisedAt(v, call)) and
|
||||
resolvedCall(call, f))
|
||||
resolvedCall(call, f)
|
||||
)
|
||||
}
|
||||
|
||||
predicate functionInitialises(Function f, GlobalVariable v)
|
||||
{
|
||||
predicate functionInitialises(Function f, GlobalVariable v) {
|
||||
exists(Call call |
|
||||
call.getEnclosingFunction() = f and
|
||||
initialisedBy(v, call))
|
||||
initialisedBy(v, call)
|
||||
)
|
||||
}
|
||||
|
||||
// this predicate is restricted to global variables used in the
|
||||
// same function as "call"
|
||||
predicate locallyUninitialisedAt(GlobalVariable v, Call call)
|
||||
{
|
||||
predicate locallyUninitialisedAt(GlobalVariable v, Call call) {
|
||||
functionInitialises(call.getEnclosingFunction(), v) and
|
||||
(
|
||||
firstCall(call)
|
||||
or
|
||||
exists(Call mid |
|
||||
locallyUninitialisedAt(v, mid) and not initialisedBy(v, mid) and callPair(mid, call))
|
||||
locallyUninitialisedAt(v, mid) and not initialisedBy(v, mid) and callPair(mid, call)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate initialisedBy(GlobalVariable v, Call call)
|
||||
{
|
||||
predicate initialisedBy(GlobalVariable v, Call call) {
|
||||
exists(Function f |
|
||||
resolvedCall(call, f) and
|
||||
initialises(v, f))
|
||||
initialises(v, f)
|
||||
)
|
||||
}
|
||||
|
||||
predicate initialises(GlobalVariable v, Function f)
|
||||
{
|
||||
predicate initialises(GlobalVariable v, Function f) {
|
||||
initFunc(v, f)
|
||||
or
|
||||
exists(Function mid | initialises(v, mid) and allCalls(f, mid))
|
||||
}
|
||||
|
||||
predicate firstCall(Call call)
|
||||
{
|
||||
beforeCall(call)
|
||||
}
|
||||
predicate firstCall(Call call) { beforeCall(call) }
|
||||
|
||||
predicate beforeCall(ControlFlowNode node)
|
||||
{
|
||||
predicate beforeCall(ControlFlowNode node) {
|
||||
exists(Function f | f.getBlock() = node)
|
||||
or
|
||||
exists(ControlFlowNode mid |
|
||||
beforeCall(mid) and
|
||||
not mid instanceof Call and
|
||||
node = mid.getASuccessor())
|
||||
node = mid.getASuccessor()
|
||||
)
|
||||
}
|
||||
|
||||
predicate callPair(Call call, Call successor)
|
||||
{
|
||||
callReaches(call, successor)
|
||||
}
|
||||
predicate callPair(Call call, Call successor) { callReaches(call, successor) }
|
||||
|
||||
predicate callReaches(Call call, ControlFlowNode successor)
|
||||
{
|
||||
predicate callReaches(Call call, ControlFlowNode successor) {
|
||||
call.getASuccessor() = successor
|
||||
or
|
||||
exists(ControlFlowNode mid |
|
||||
callReaches(call, mid) and
|
||||
not mid instanceof Call
|
||||
and mid.getASuccessor() = successor)
|
||||
not mid instanceof Call and
|
||||
mid.getASuccessor() = successor
|
||||
)
|
||||
}
|
||||
|
||||
from GlobalVariable v, Function f
|
||||
where uninitialisedBefore(v, f)
|
||||
and useFunc(v, f)
|
||||
select f, "The variable '" + v.getName() + " is used in this function but may not be initialized when it is called."
|
||||
where
|
||||
uninitialisedBefore(v, f) and
|
||||
useFunc(v, f)
|
||||
select f,
|
||||
"The variable '" + v.getName() +
|
||||
" is used in this function but may not be initialized when it is called."
|
||||
|
||||
@@ -8,16 +8,22 @@
|
||||
* security
|
||||
* external/cwe/cwe-476
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
from LocalScopeVariable v, ControlFlowNode def,
|
||||
VariableAccess checked, VariableAccess unchecked
|
||||
where checked = v.getAnAccess() and dereferenced(checked)
|
||||
and unchecked = v.getAnAccess() and dereferenced(unchecked)
|
||||
and definitionUsePair(v, def, checked)
|
||||
and definitionUsePair(v, def, unchecked)
|
||||
and checkedValid(v, checked)
|
||||
and not(checkedValid(v, unchecked))
|
||||
and not(unchecked.getParent+() instanceof SizeofOperator)
|
||||
and forall(ControlFlowNode other | definitionUsePair(v, other, checked) | definitionUsePair(v, other, unchecked))
|
||||
select unchecked, "This dereference is not guarded by a non-null check, whereas other dereferences are guarded"
|
||||
from LocalScopeVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked
|
||||
where
|
||||
checked = v.getAnAccess() and
|
||||
dereferenced(checked) and
|
||||
unchecked = v.getAnAccess() and
|
||||
dereferenced(unchecked) and
|
||||
definitionUsePair(v, def, checked) and
|
||||
definitionUsePair(v, def, unchecked) and
|
||||
checkedValid(v, checked) and
|
||||
not checkedValid(v, unchecked) and
|
||||
not unchecked.getParent+() instanceof SizeofOperator and
|
||||
forall(ControlFlowNode other | definitionUsePair(v, other, checked) |
|
||||
definitionUsePair(v, other, unchecked)
|
||||
)
|
||||
select unchecked,
|
||||
"This dereference is not guarded by a non-null check, whereas other dereferences are guarded"
|
||||
|
||||
@@ -8,36 +8,35 @@
|
||||
* security
|
||||
* external/cwe/cwe-456
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.pointsto.CallGraph
|
||||
|
||||
predicate global(GlobalVariable v)
|
||||
{
|
||||
not exists(v.getInitializer())
|
||||
and not v.getType() instanceof ArrayType
|
||||
and not v.getType() instanceof Class
|
||||
and v.getAnAccess().isUsedAsLValue()
|
||||
predicate global(GlobalVariable v) {
|
||||
not exists(v.getInitializer()) and
|
||||
not v.getType() instanceof ArrayType and
|
||||
not v.getType() instanceof Class and
|
||||
v.getAnAccess().isUsedAsLValue()
|
||||
}
|
||||
|
||||
predicate mainCalled(Function f)
|
||||
{
|
||||
predicate mainCalled(Function f) {
|
||||
f.getQualifiedName() = "main"
|
||||
or
|
||||
exists(Function caller |
|
||||
mainCalled(caller) and allCalls(caller, f))
|
||||
exists(Function caller | mainCalled(caller) and allCalls(caller, f))
|
||||
}
|
||||
|
||||
predicate called(Function f)
|
||||
{
|
||||
predicate called(Function f) {
|
||||
mainCalled(f)
|
||||
or
|
||||
exists(FunctionAccess fa | fa.getTarget() = f)
|
||||
}
|
||||
|
||||
from GlobalVariable v
|
||||
where global(v)
|
||||
and not exists(VariableAccess lval |
|
||||
v.getAnAccess() = lval and lval.isUsedAsLValue() and
|
||||
called(lval.getEnclosingFunction())
|
||||
)
|
||||
where
|
||||
global(v) and
|
||||
not exists(VariableAccess lval |
|
||||
v.getAnAccess() = lval and
|
||||
lval.isUsedAsLValue() and
|
||||
called(lval.getEnclosingFunction())
|
||||
)
|
||||
select v, "Initialization code for '" + v.getName() + "' is never run."
|
||||
|
||||
@@ -10,15 +10,17 @@
|
||||
* statistical
|
||||
* non-attributable
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
from Function f, Parameter p, Type t, int size
|
||||
where f.getAParameter() = p
|
||||
and p.getType() = t
|
||||
and t.getSize() = size
|
||||
and size > 64
|
||||
and not t.getUnderlyingType() instanceof ArrayType
|
||||
and not f instanceof CopyAssignmentOperator
|
||||
select
|
||||
p, "This parameter of type $@ is " + size.toString() + " bytes - consider passing a const pointer/reference instead.",
|
||||
t, t.toString()
|
||||
where
|
||||
f.getAParameter() = p and
|
||||
p.getType() = t and
|
||||
t.getSize() = size and
|
||||
size > 64 and
|
||||
not t.getUnderlyingType() instanceof ArrayType and
|
||||
not f instanceof CopyAssignmentOperator
|
||||
select p,
|
||||
"This parameter of type $@ is " + size.toString() +
|
||||
" bytes - consider passing a const pointer/reference instead.", t, t.toString()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @name Pointer offset used before it is checked
|
||||
* @description Accessing a pointer or array using an offset before
|
||||
* checking if the value is positive
|
||||
* @description Accessing a pointer or array using an offset before
|
||||
* checking if the value is positive
|
||||
* may result in unexpected behavior.
|
||||
* @kind problem
|
||||
* @id cpp/late-negative-test
|
||||
@@ -10,32 +10,42 @@
|
||||
* security
|
||||
* external/cwe/cwe-823
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op)
|
||||
{
|
||||
predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op) {
|
||||
exists(int varindex, string constant, Literal lit |
|
||||
op.getChild(varindex) = v.getAnAccess() and
|
||||
op.getChild(1 - varindex) = lit and
|
||||
lit.getValue() = constant and
|
||||
(
|
||||
(op.getOperator() = "<" and varindex = 0 and constant = "0") or
|
||||
(op.getOperator() = "<" and varindex = 1 and constant = "-1") or
|
||||
(op.getOperator() = ">" and varindex = 0 and constant = "-1") or
|
||||
(op.getOperator() = ">" and varindex = 1 and constant = "0") or
|
||||
(op.getOperator() = "<=" and varindex = 0 and constant = "-1") or
|
||||
(op.getOperator() = "<=" and varindex = 1 and constant = "0") or
|
||||
(op.getOperator() = ">=" and varindex = 0 and constant = "0") or
|
||||
(op.getOperator() = ">=" and varindex = 1 and constant = "-1")
|
||||
op.getOperator() = "<" and varindex = 0 and constant = "0"
|
||||
or
|
||||
op.getOperator() = "<" and varindex = 1 and constant = "-1"
|
||||
or
|
||||
op.getOperator() = ">" and varindex = 0 and constant = "-1"
|
||||
or
|
||||
op.getOperator() = ">" and varindex = 1 and constant = "0"
|
||||
or
|
||||
op.getOperator() = "<=" and varindex = 0 and constant = "-1"
|
||||
or
|
||||
op.getOperator() = "<=" and varindex = 1 and constant = "0"
|
||||
or
|
||||
op.getOperator() = ">=" and varindex = 0 and constant = "0"
|
||||
or
|
||||
op.getOperator() = ">=" and varindex = 1 and constant = "-1"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
from LocalScopeVariable v, ArrayExpr dangerous, Expr check
|
||||
where useUsePair(v, dangerous.getArrayOffset(), check.getAChild())
|
||||
and negativeCheck(v, check)
|
||||
and not exists(Expr other | negativeCheck(v, other) and useUsePair(v, other.getAChild(), dangerous.getArrayOffset()))
|
||||
where
|
||||
useUsePair(v, dangerous.getArrayOffset(), check.getAChild()) and
|
||||
negativeCheck(v, check) and
|
||||
not exists(Expr other |
|
||||
negativeCheck(v, other) and useUsePair(v, other.getAChild(), dangerous.getArrayOffset())
|
||||
)
|
||||
select dangerous,
|
||||
"Variable '" + v.getName() +
|
||||
"' is used as an array-offset before it is tested for being negative (test on line " +
|
||||
check.getLocation().getStartLine().toString() + "). "
|
||||
"' is used as an array-offset before it is tested for being negative (test on line " +
|
||||
check.getLocation().getStartLine().toString() + "). "
|
||||
|
||||
@@ -1,33 +1,27 @@
|
||||
/** Provides helpers for OverflowStatic.ql */
|
||||
|
||||
import cpp
|
||||
|
||||
class ZeroAssignment extends AssignExpr
|
||||
{
|
||||
class ZeroAssignment extends AssignExpr {
|
||||
ZeroAssignment() {
|
||||
this.getAnOperand() instanceof VariableAccess and
|
||||
this.getAnOperand() instanceof Zero
|
||||
}
|
||||
|
||||
Variable assignedVariable() {
|
||||
result.getAnAccess() = this.getAnOperand()
|
||||
}
|
||||
Variable assignedVariable() { result.getAnAccess() = this.getAnOperand() }
|
||||
}
|
||||
|
||||
private predicate staticLimit(RelationalOperation op, Variable v, int limit)
|
||||
{
|
||||
(
|
||||
op instanceof LTExpr and
|
||||
op.getLeftOperand() = v.getAnAccess() and
|
||||
op.getRightOperand().getValue().toInt() - 1 = limit
|
||||
) or (
|
||||
op instanceof LEExpr and
|
||||
op.getLeftOperand() = v.getAnAccess() and
|
||||
op.getRightOperand().getValue().toInt() = limit
|
||||
)
|
||||
private predicate staticLimit(RelationalOperation op, Variable v, int limit) {
|
||||
op instanceof LTExpr and
|
||||
op.getLeftOperand() = v.getAnAccess() and
|
||||
op.getRightOperand().getValue().toInt() - 1 = limit
|
||||
or
|
||||
op instanceof LEExpr and
|
||||
op.getLeftOperand() = v.getAnAccess() and
|
||||
op.getRightOperand().getValue().toInt() = limit
|
||||
}
|
||||
|
||||
private predicate simpleInc(IncrementOperation inc, Variable v)
|
||||
{
|
||||
private predicate simpleInc(IncrementOperation inc, Variable v) {
|
||||
inc.getAChild() = v.getAnAccess()
|
||||
}
|
||||
|
||||
@@ -35,8 +29,7 @@ private predicate simpleInc(IncrementOperation inc, Variable v)
|
||||
* A `for` loop of the form `for (x = 0; x < limit; x++)` with no modification
|
||||
* of `x` in the body. Variations with `<=` and `++x` are allowed.
|
||||
*/
|
||||
class ClassicForLoop extends ForStmt
|
||||
{
|
||||
class ClassicForLoop extends ForStmt {
|
||||
ClassicForLoop() {
|
||||
exists(LocalVariable v |
|
||||
this.getInitialization().getAChild() instanceof ZeroAssignment and
|
||||
@@ -51,13 +44,11 @@ class ClassicForLoop extends ForStmt
|
||||
}
|
||||
|
||||
/** Gets the loop variable. */
|
||||
LocalVariable counter() {
|
||||
simpleInc(this.getUpdate(), result)
|
||||
}
|
||||
LocalVariable counter() { simpleInc(this.getUpdate(), result) }
|
||||
|
||||
/** Gets the maximum value that the loop variable may have inside the loop
|
||||
* body. The minimum is 0. */
|
||||
int limit() {
|
||||
staticLimit(this.getCondition(), _, result)
|
||||
}
|
||||
/**
|
||||
* Gets the maximum value that the loop variable may have inside the loop
|
||||
* body. The minimum is 0.
|
||||
*/
|
||||
int limit() { staticLimit(this.getCondition(), _, result) }
|
||||
}
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
import semmle.code.cpp.pointsto.PointsTo
|
||||
|
||||
private predicate freed(Expr e)
|
||||
{
|
||||
private predicate freed(Expr e) {
|
||||
exists(FunctionCall fc, Expr arg |
|
||||
freeCall(fc, arg) and
|
||||
arg = e
|
||||
) or exists(DeleteExpr de |
|
||||
de.getExpr() = e
|
||||
) or exists(DeleteArrayExpr de |
|
||||
de.getExpr() = e
|
||||
) or exists(ExprCall c |
|
||||
)
|
||||
or
|
||||
exists(DeleteExpr de | de.getExpr() = e)
|
||||
or
|
||||
exists(DeleteArrayExpr de | de.getExpr() = e)
|
||||
or
|
||||
exists(ExprCall c |
|
||||
// cautiously assume that any ExprCall could be a freeCall.
|
||||
c.getAnArgument() = e
|
||||
)
|
||||
}
|
||||
|
||||
class FreedExpr extends PointsToExpr
|
||||
{
|
||||
class FreedExpr extends PointsToExpr {
|
||||
FreedExpr() { freed(this) }
|
||||
|
||||
override predicate interesting() { freed(this) }
|
||||
}
|
||||
|
||||
predicate allocMayBeFreed(Expr alloc) {
|
||||
isAllocationExpr(alloc) and anythingPointsTo(alloc)
|
||||
}
|
||||
predicate allocMayBeFreed(Expr alloc) { isAllocationExpr(alloc) and anythingPointsTo(alloc) }
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* security
|
||||
* external/cwe/cwe-401
|
||||
*/
|
||||
|
||||
import MemoryFreed
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
|
||||
@@ -15,29 +16,27 @@ import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
* 'call' is either a direct call to f, or a possible call to f
|
||||
* via a function pointer.
|
||||
*/
|
||||
predicate mayCallFunction(Expr call, Function f)
|
||||
{
|
||||
predicate mayCallFunction(Expr call, Function f) {
|
||||
call.(FunctionCall).getTarget() = f or
|
||||
call.(VariableCall).getVariable().getAnAssignedValue().getAChild*().(FunctionAccess).getTarget() = f
|
||||
call.(VariableCall).getVariable().getAnAssignedValue().getAChild*().(FunctionAccess).getTarget() =
|
||||
f
|
||||
}
|
||||
|
||||
predicate allocCallOrIndirect(Expr e)
|
||||
{
|
||||
(
|
||||
// direct alloc call
|
||||
isAllocationExpr(e) and
|
||||
|
||||
// We are only interested in alloc calls that are
|
||||
// actually freed somehow, as MemoryNeverFreed
|
||||
// will catch those that aren't.
|
||||
allocMayBeFreed(e)
|
||||
) or exists(ReturnStmt rtn |
|
||||
predicate allocCallOrIndirect(Expr e) {
|
||||
// direct alloc call
|
||||
isAllocationExpr(e) and
|
||||
// We are only interested in alloc calls that are
|
||||
// actually freed somehow, as MemoryNeverFreed
|
||||
// will catch those that aren't.
|
||||
allocMayBeFreed(e)
|
||||
or
|
||||
exists(ReturnStmt rtn |
|
||||
// indirect alloc call
|
||||
mayCallFunction(e, rtn.getEnclosingFunction()) and
|
||||
(
|
||||
// return alloc
|
||||
allocCallOrIndirect(rtn.getExpr()) or
|
||||
|
||||
allocCallOrIndirect(rtn.getExpr())
|
||||
or
|
||||
// return variable assigned with alloc
|
||||
exists(Variable v |
|
||||
v = rtn.getExpr().(VariableAccess).getTarget() and
|
||||
@@ -53,8 +52,7 @@ predicate allocCallOrIndirect(Expr e)
|
||||
* succeed. A failed realloc does *not* free the input pointer, which
|
||||
* can cause memory leaks.
|
||||
*/
|
||||
predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode verified)
|
||||
{
|
||||
predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode verified) {
|
||||
reallocCall.getTarget().hasQualifiedName("realloc") and
|
||||
reallocCall.getArgument(0) = v.getAnAccess() and
|
||||
(
|
||||
@@ -64,35 +62,33 @@ predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode
|
||||
newV.getAnAssignedValue() = reallocCall and
|
||||
node.(AnalysedExpr).getNonNullSuccessor(newV) = verified and
|
||||
// note: this case uses naive flow logic (getAnAssignedValue).
|
||||
|
||||
// special case: if the result of the 'realloc' is assigned to the
|
||||
// same variable, we don't descriminate properly between the old
|
||||
// and the new allocation; better to not consider this a free at
|
||||
// all in that case.
|
||||
newV != v
|
||||
) or (
|
||||
// a realloc(ptr, 0), which always succeeds and frees
|
||||
// (return the realloc itself)
|
||||
reallocCall.getArgument(1).getValue() = "0" and
|
||||
verified = reallocCall
|
||||
)
|
||||
or
|
||||
// a realloc(ptr, 0), which always succeeds and frees
|
||||
// (return the realloc itself)
|
||||
reallocCall.getArgument(1).getValue() = "0" and
|
||||
verified = reallocCall
|
||||
)
|
||||
}
|
||||
|
||||
predicate freeCallOrIndirect(ControlFlowNode n, Variable v)
|
||||
{
|
||||
(
|
||||
// direct free call
|
||||
freeCall(n, v.getAnAccess()) and
|
||||
not n.(FunctionCall).getTarget().hasQualifiedName("realloc")
|
||||
) or (
|
||||
// verified realloc call
|
||||
verifiedRealloc(_, v, n)
|
||||
) or (
|
||||
n.(DeleteExpr).getExpr() = v.getAnAccess()
|
||||
) or (
|
||||
n.(DeleteArrayExpr).getExpr() = v.getAnAccess()
|
||||
) or exists(FunctionCall midcall, Function mid, int arg |
|
||||
predicate freeCallOrIndirect(ControlFlowNode n, Variable v) {
|
||||
// direct free call
|
||||
freeCall(n, v.getAnAccess()) and
|
||||
not n.(FunctionCall).getTarget().hasQualifiedName("realloc")
|
||||
or
|
||||
// verified realloc call
|
||||
verifiedRealloc(_, v, n)
|
||||
or
|
||||
n.(DeleteExpr).getExpr() = v.getAnAccess()
|
||||
or
|
||||
n.(DeleteArrayExpr).getExpr() = v.getAnAccess()
|
||||
or
|
||||
exists(FunctionCall midcall, Function mid, int arg |
|
||||
// indirect free call
|
||||
n.(Call).getArgument(arg) = v.getAnAccess() and
|
||||
mayCallFunction(n, mid) and
|
||||
@@ -101,11 +97,8 @@ predicate freeCallOrIndirect(ControlFlowNode n, Variable v)
|
||||
)
|
||||
}
|
||||
|
||||
predicate allocationDefinition(LocalScopeVariable v, ControlFlowNode def)
|
||||
{
|
||||
exists(Expr expr |
|
||||
exprDefinition(v, def, expr) and allocCallOrIndirect(expr)
|
||||
)
|
||||
predicate allocationDefinition(LocalScopeVariable v, ControlFlowNode def) {
|
||||
exists(Expr expr | exprDefinition(v, def, expr) and allocCallOrIndirect(expr))
|
||||
}
|
||||
|
||||
class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassignment {
|
||||
@@ -116,11 +109,10 @@ class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassi
|
||||
}
|
||||
|
||||
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
|
||||
// node may be used in allocationReaches
|
||||
// node may be used in allocationReaches
|
||||
exists(node.(AnalysedExpr).getNullSuccessor(v)) or
|
||||
freeCallOrIndirect(node, v) or
|
||||
assignedToFieldOrGlobal(v, node) or
|
||||
|
||||
// node may be used directly in query
|
||||
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
|
||||
}
|
||||
@@ -133,17 +125,14 @@ class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassi
|
||||
/**
|
||||
* The value from allocation `def` is still held in Variable `v` upon entering `node`.
|
||||
*/
|
||||
predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node)
|
||||
{
|
||||
predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) {
|
||||
exists(AllocVariableReachability r |
|
||||
// reachability
|
||||
r.reachesTo(def, _, node, v) or
|
||||
|
||||
r.reachesTo(def, _, node, v)
|
||||
or
|
||||
// accept def node itself
|
||||
(
|
||||
r.isSource(def, v) and
|
||||
node = def
|
||||
)
|
||||
r.isSource(def, v) and
|
||||
node = def
|
||||
)
|
||||
}
|
||||
|
||||
@@ -158,10 +147,11 @@ class AllocReachability extends LocalScopeVariableReachabilityExt {
|
||||
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v) {
|
||||
override predicate isBarrier(
|
||||
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
|
||||
) {
|
||||
isSource(source, v) and
|
||||
next = node.getASuccessor() and
|
||||
|
||||
// the memory (stored in any variable `v0`) allocated at `source` is freed or
|
||||
// assigned to a global at node, or NULL checked on the edge node -> next.
|
||||
exists(LocalScopeVariable v0 | allocatedVariableReaches(v0, source, node) |
|
||||
@@ -177,30 +167,26 @@ class AllocReachability extends LocalScopeVariableReachabilityExt {
|
||||
* or potentially leaked globally upon reaching `node` (regardless of what variable
|
||||
* it's still held in, if any).
|
||||
*/
|
||||
predicate allocationReaches(ControlFlowNode def, ControlFlowNode node)
|
||||
{
|
||||
exists(AllocReachability r |
|
||||
r.reaches(def, _, node)
|
||||
)
|
||||
predicate allocationReaches(ControlFlowNode def, ControlFlowNode node) {
|
||||
exists(AllocReachability r | r.reaches(def, _, node))
|
||||
}
|
||||
|
||||
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e)
|
||||
{
|
||||
(
|
||||
// assigned to anything except a LocalScopeVariable
|
||||
// (typically a field or global, but for example also *ptr = v)
|
||||
e.(Assignment).getRValue() = v.getAnAccess() and
|
||||
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
|
||||
) or exists(Expr midExpr, Function mid, int arg |
|
||||
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
|
||||
// assigned to anything except a LocalScopeVariable
|
||||
// (typically a field or global, but for example also *ptr = v)
|
||||
e.(Assignment).getRValue() = v.getAnAccess() and
|
||||
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
|
||||
or
|
||||
exists(Expr midExpr, Function mid, int arg |
|
||||
// indirect assignment
|
||||
e.(FunctionCall).getArgument(arg) = v.getAnAccess() and
|
||||
mayCallFunction(e, mid) and
|
||||
midExpr.getEnclosingFunction() = mid and
|
||||
assignedToFieldOrGlobal(mid.getParameter(arg), midExpr)
|
||||
) or (
|
||||
// assigned to a field via constructor field initializer
|
||||
e.(ConstructorFieldInit).getExpr() = v.getAnAccess()
|
||||
)
|
||||
or
|
||||
// assigned to a field via constructor field initializer
|
||||
e.(ConstructorFieldInit).getExpr() = v.getAnAccess()
|
||||
}
|
||||
|
||||
from ControlFlowNode def, ReturnStmt ret
|
||||
@@ -210,6 +196,4 @@ where
|
||||
allocatedVariableReaches(v, def, ret) and
|
||||
ret.getAChild*() = v.getAnAccess()
|
||||
)
|
||||
select
|
||||
def, "The memory allocated here may not be released at $@.",
|
||||
ret, "this exit point"
|
||||
select def, "The memory allocated here may not be released at $@.", ret, "this exit point"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* security
|
||||
* external/cwe/cwe-401
|
||||
*/
|
||||
|
||||
import MemoryFreed
|
||||
|
||||
from Expr alloc
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @name Unchecked return value used as offset
|
||||
* @description Using a return value as a pointer offset without checking that the value is positive
|
||||
* @description Using a return value as a pointer offset without checking that the value is positive
|
||||
* may lead to buffer overruns.
|
||||
* @kind problem
|
||||
* @id cpp/missing-negativity-test
|
||||
@@ -9,59 +9,63 @@
|
||||
* security
|
||||
* external/cwe/cwe-823
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import Negativity
|
||||
|
||||
class IntegralReturnValue extends FunctionCall
|
||||
{
|
||||
IntegralReturnValue() {
|
||||
this.getType().getUnderlyingType() instanceof IntegralType
|
||||
}
|
||||
class IntegralReturnValue extends FunctionCall {
|
||||
IntegralReturnValue() { this.getType().getUnderlyingType() instanceof IntegralType }
|
||||
|
||||
predicate isChecked() {
|
||||
exists(ControlFlowNode def, ControlFlowNode test, Variable v |
|
||||
exprDefinition(v, def, this) and
|
||||
definitionReaches(def, test) and
|
||||
errorSuccessor(v, test.getASuccessor()))
|
||||
errorSuccessor(v, test.getASuccessor())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class FunctionWithNegativeReturn extends Function
|
||||
{
|
||||
class FunctionWithNegativeReturn extends Function {
|
||||
FunctionWithNegativeReturn() {
|
||||
this.getType().getUnderlyingType() instanceof IntegralType and
|
||||
( exists(ReturnStmt ret |
|
||||
(
|
||||
exists(ReturnStmt ret |
|
||||
ret.getExpr().getValue().toInt() < 0 and
|
||||
ret.getEnclosingFunction() = this)
|
||||
ret.getEnclosingFunction() = this
|
||||
)
|
||||
or
|
||||
count(IntegralReturnValue val | val.getTarget() = this and val.isChecked()) * 100 /
|
||||
count(IntegralReturnValue val | val.getTarget() = this) >= 80)
|
||||
count(IntegralReturnValue val | val.getTarget() = this) >= 80
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate dangerousUse(IntegralReturnValue val, Expr use)
|
||||
{
|
||||
predicate dangerousUse(IntegralReturnValue val, Expr use) {
|
||||
exists(ArrayExpr ae | ae.getArrayOffset() = val and use = val)
|
||||
or
|
||||
exists(LocalScopeVariable v, ControlFlowNode def, ArrayExpr ae |
|
||||
exprDefinition(v, def, val) and
|
||||
use = ae.getArrayOffset() and
|
||||
not boundsChecked(v, use) and
|
||||
definitionUsePair(v, def, use))
|
||||
definitionUsePair(v, def, use)
|
||||
)
|
||||
or
|
||||
(use.getParent().(AddExpr).getAnOperand() = val and
|
||||
val = use and
|
||||
use.getType().getUnderlyingType() instanceof PointerType)
|
||||
use.getParent().(AddExpr).getAnOperand() = val and
|
||||
val = use and
|
||||
use.getType().getUnderlyingType() instanceof PointerType
|
||||
or
|
||||
exists(LocalScopeVariable v, ControlFlowNode def, AddExpr add |
|
||||
exprDefinition(v, def, val) and
|
||||
definitionUsePair(v, def, use) and
|
||||
add.getAnOperand() = use and
|
||||
not boundsChecked(v, use) and
|
||||
add.getType().getUnderlyingType() instanceof PointerType)
|
||||
add.getType().getUnderlyingType() instanceof PointerType
|
||||
)
|
||||
}
|
||||
|
||||
from FunctionWithNegativeReturn f, IntegralReturnValue val, Expr dangerous
|
||||
where val.getTarget() = f
|
||||
and dangerousUse(val, dangerous)
|
||||
select dangerous, "Dangerous use of possibly negative value (return value of '" + f.getName() + "')."
|
||||
where
|
||||
val.getTarget() = f and
|
||||
dangerousUse(val, dangerous)
|
||||
select dangerous,
|
||||
"Dangerous use of possibly negative value (return value of '" + f.getName() + "')."
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
* security
|
||||
* external/cwe/cwe-476
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
from VariableAccess access
|
||||
where maybeNull(access)
|
||||
and dereferenced(access)
|
||||
where
|
||||
maybeNull(access) and
|
||||
dereferenced(access)
|
||||
select access, "Value may be null; it should be checked before dereferencing."
|
||||
|
||||
@@ -1,111 +1,150 @@
|
||||
import cpp
|
||||
|
||||
predicate valueOfVar(Variable v, Expr val)
|
||||
{
|
||||
predicate valueOfVar(Variable v, Expr val) {
|
||||
val = v.getAnAccess() or
|
||||
val.(AssignExpr).getLValue() = v.getAnAccess()
|
||||
}
|
||||
|
||||
predicate boundsCheckExpr(Variable v, Expr cond)
|
||||
{
|
||||
exists(EQExpr eq | cond = eq and
|
||||
eq.getAnOperand().getValue() = "-1" and valueOfVar(v, eq.getAnOperand()))
|
||||
predicate boundsCheckExpr(Variable v, Expr cond) {
|
||||
exists(EQExpr eq |
|
||||
cond = eq and
|
||||
eq.getAnOperand().getValue() = "-1" and
|
||||
valueOfVar(v, eq.getAnOperand())
|
||||
)
|
||||
or
|
||||
exists(NEExpr ne | cond = ne and
|
||||
ne.getAnOperand().getValue() = "-1" and valueOfVar(v, ne.getAnOperand()))
|
||||
exists(NEExpr ne |
|
||||
cond = ne and
|
||||
ne.getAnOperand().getValue() = "-1" and
|
||||
valueOfVar(v, ne.getAnOperand())
|
||||
)
|
||||
or
|
||||
exists(LTExpr lt | cond = lt and
|
||||
valueOfVar(v, lt.getAnOperand()) and exists(lt.getAnOperand().getValue()))
|
||||
exists(LTExpr lt |
|
||||
cond = lt and
|
||||
valueOfVar(v, lt.getAnOperand()) and
|
||||
exists(lt.getAnOperand().getValue())
|
||||
)
|
||||
or
|
||||
exists(LEExpr le | cond = le and
|
||||
valueOfVar(v, le.getAnOperand()) and exists(le.getAnOperand().getValue()))
|
||||
exists(LEExpr le |
|
||||
cond = le and
|
||||
valueOfVar(v, le.getAnOperand()) and
|
||||
exists(le.getAnOperand().getValue())
|
||||
)
|
||||
or
|
||||
exists(GTExpr gt | cond = gt and
|
||||
valueOfVar(v, gt.getAnOperand()) and exists(gt.getAnOperand().getValue()))
|
||||
exists(GTExpr gt |
|
||||
cond = gt and
|
||||
valueOfVar(v, gt.getAnOperand()) and
|
||||
exists(gt.getAnOperand().getValue())
|
||||
)
|
||||
or
|
||||
exists(GEExpr ge | cond = ge and
|
||||
valueOfVar(v, ge.getAnOperand()) and exists(ge.getAnOperand().getValue()))
|
||||
exists(GEExpr ge |
|
||||
cond = ge and
|
||||
valueOfVar(v, ge.getAnOperand()) and
|
||||
exists(ge.getAnOperand().getValue())
|
||||
)
|
||||
}
|
||||
|
||||
predicate conditionalSuccessor(ControlFlowNode node, ControlFlowNode succ)
|
||||
{
|
||||
if node.isCondition() then
|
||||
(succ = node.getATrueSuccessor() or succ = node.getAFalseSuccessor())
|
||||
predicate conditionalSuccessor(ControlFlowNode node, ControlFlowNode succ) {
|
||||
if node.isCondition()
|
||||
then succ = node.getATrueSuccessor() or succ = node.getAFalseSuccessor()
|
||||
else
|
||||
exists(BinaryLogicalOperation binop |
|
||||
binop.getAnOperand() = node and conditionalSuccessor(binop, succ))
|
||||
binop.getAnOperand() = node and conditionalSuccessor(binop, succ)
|
||||
)
|
||||
}
|
||||
|
||||
predicate boundsChecked(Variable v, ControlFlowNode node)
|
||||
{
|
||||
predicate boundsChecked(Variable v, ControlFlowNode node) {
|
||||
exists(Expr test |
|
||||
boundsCheckExpr(v, test) and
|
||||
conditionalSuccessor(test, node))
|
||||
conditionalSuccessor(test, node)
|
||||
)
|
||||
or
|
||||
exists(ControlFlowNode mid |
|
||||
boundsChecked(v, mid) and mid = node.getAPredecessor() and not definitionBarrier(v, mid))
|
||||
boundsChecked(v, mid) and mid = node.getAPredecessor() and not definitionBarrier(v, mid)
|
||||
)
|
||||
}
|
||||
|
||||
predicate errorCondition(Variable v, Expr cond)
|
||||
{
|
||||
exists(EQExpr eq | cond = eq and
|
||||
eq.getAnOperand().getValue() = "-1" and eq.getAnOperand() = v.getAnAccess())
|
||||
predicate errorCondition(Variable v, Expr cond) {
|
||||
exists(EQExpr eq |
|
||||
cond = eq and
|
||||
eq.getAnOperand().getValue() = "-1" and
|
||||
eq.getAnOperand() = v.getAnAccess()
|
||||
)
|
||||
or
|
||||
exists(LTExpr lt | cond = lt and
|
||||
lt.getLeftOperand() = v.getAnAccess() and lt.getRightOperand().getValue() = "0")
|
||||
exists(LTExpr lt |
|
||||
cond = lt and
|
||||
lt.getLeftOperand() = v.getAnAccess() and
|
||||
lt.getRightOperand().getValue() = "0"
|
||||
)
|
||||
or
|
||||
exists(LEExpr le | cond = le and
|
||||
le.getRightOperand() = v.getAnAccess() and le.getRightOperand().getValue() = "-1")
|
||||
exists(LEExpr le |
|
||||
cond = le and
|
||||
le.getRightOperand() = v.getAnAccess() and
|
||||
le.getRightOperand().getValue() = "-1"
|
||||
)
|
||||
or
|
||||
exists(NotExpr ne | cond = ne and
|
||||
successCondition(v, ne.getOperand()))
|
||||
exists(NotExpr ne |
|
||||
cond = ne and
|
||||
successCondition(v, ne.getOperand())
|
||||
)
|
||||
}
|
||||
|
||||
predicate successCondition(Variable v, Expr cond)
|
||||
{
|
||||
exists(NEExpr ne | cond = ne and
|
||||
ne.getAnOperand().getValue() = "-1" and ne.getAnOperand() = v.getAnAccess())
|
||||
predicate successCondition(Variable v, Expr cond) {
|
||||
exists(NEExpr ne |
|
||||
cond = ne and
|
||||
ne.getAnOperand().getValue() = "-1" and
|
||||
ne.getAnOperand() = v.getAnAccess()
|
||||
)
|
||||
or
|
||||
exists(GEExpr ge | cond = ge and
|
||||
ge.getLeftOperand() = v.getAnAccess() and ge.getRightOperand().getValue() = "0")
|
||||
exists(GEExpr ge |
|
||||
cond = ge and
|
||||
ge.getLeftOperand() = v.getAnAccess() and
|
||||
ge.getRightOperand().getValue() = "0"
|
||||
)
|
||||
or
|
||||
exists(GTExpr gt | cond = gt and
|
||||
gt.getRightOperand() = v.getAnAccess() and gt.getRightOperand().getValue() = "-1")
|
||||
exists(GTExpr gt |
|
||||
cond = gt and
|
||||
gt.getRightOperand() = v.getAnAccess() and
|
||||
gt.getRightOperand().getValue() = "-1"
|
||||
)
|
||||
or
|
||||
exists(NotExpr ne | cond = ne and
|
||||
errorCondition(v, ne.getOperand()))
|
||||
exists(NotExpr ne |
|
||||
cond = ne and
|
||||
errorCondition(v, ne.getOperand())
|
||||
)
|
||||
}
|
||||
|
||||
predicate errorSuccessor(Variable v, ControlFlowNode n)
|
||||
{
|
||||
predicate errorSuccessor(Variable v, ControlFlowNode n) {
|
||||
exists(Expr cond |
|
||||
(errorCondition(v, cond) and n = cond.getATrueSuccessor()) or
|
||||
(successCondition(v, cond) and n = cond.getAFalseSuccessor()))
|
||||
errorCondition(v, cond) and n = cond.getATrueSuccessor()
|
||||
or
|
||||
successCondition(v, cond) and n = cond.getAFalseSuccessor()
|
||||
)
|
||||
}
|
||||
|
||||
predicate successSuccessor(Variable v, ControlFlowNode n)
|
||||
{
|
||||
predicate successSuccessor(Variable v, ControlFlowNode n) {
|
||||
exists(Expr cond |
|
||||
(successCondition(v, cond) and n = cond.getATrueSuccessor()) or
|
||||
(errorCondition(v, cond) and n = cond.getAFalseSuccessor()))
|
||||
successCondition(v, cond) and n = cond.getATrueSuccessor()
|
||||
or
|
||||
errorCondition(v, cond) and n = cond.getAFalseSuccessor()
|
||||
)
|
||||
}
|
||||
|
||||
predicate checkedError(Variable v, ControlFlowNode n)
|
||||
{
|
||||
predicate checkedError(Variable v, ControlFlowNode n) {
|
||||
errorSuccessor(v, n)
|
||||
or
|
||||
exists(ControlFlowNode mid |
|
||||
checkedError(v, mid) and
|
||||
n = mid.getASuccessor() and
|
||||
not definitionBarrier(v, mid))
|
||||
not definitionBarrier(v, mid)
|
||||
)
|
||||
}
|
||||
|
||||
predicate checkedSuccess(Variable v, ControlFlowNode n)
|
||||
{
|
||||
predicate checkedSuccess(Variable v, ControlFlowNode n) {
|
||||
successSuccessor(v, n)
|
||||
or
|
||||
exists(ControlFlowNode mid |
|
||||
checkedSuccess(v, mid) and
|
||||
n = mid.getASuccessor() and
|
||||
not definitionBarrier(v, mid))
|
||||
not definitionBarrier(v, mid)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,12 +7,11 @@
|
||||
* @id cpp/new-array-delete-mismatch
|
||||
* @tags reliability
|
||||
*/
|
||||
|
||||
import NewDelete
|
||||
|
||||
from Expr alloc, Expr free, Expr freed
|
||||
where
|
||||
allocReaches(freed, alloc, "new[]") and
|
||||
freeExprOrIndirect(free, freed, "delete")
|
||||
select
|
||||
free, "This memory may have been allocated with '$@', not 'new'.",
|
||||
alloc, "new[]"
|
||||
select free, "This memory may have been allocated with '$@', not 'new'.", alloc, "new[]"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* Provides predicates for associating new/malloc calls with delete/free.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.SSA
|
||||
import semmle.code.cpp.dataflow.DataFlow
|
||||
@@ -12,24 +13,20 @@ import semmle.code.cpp.dataflow.DataFlow
|
||||
predicate allocExpr(Expr alloc, string kind) {
|
||||
isAllocationExpr(alloc) and
|
||||
(
|
||||
(
|
||||
alloc instanceof FunctionCall and
|
||||
kind = "malloc"
|
||||
) or (
|
||||
alloc instanceof NewExpr and
|
||||
kind = "new" and
|
||||
|
||||
// exclude placement new and custom overloads as they
|
||||
// may not conform to assumptions
|
||||
not alloc.(NewExpr).getAllocatorCall().getTarget().getNumberOfParameters() > 1
|
||||
) or (
|
||||
alloc instanceof NewArrayExpr and
|
||||
kind = "new[]" and
|
||||
|
||||
// exclude placement new and custom overloads as they
|
||||
// may not conform to assumptions
|
||||
not alloc.(NewArrayExpr).getAllocatorCall().getTarget().getNumberOfParameters() > 1
|
||||
)
|
||||
alloc instanceof FunctionCall and
|
||||
kind = "malloc"
|
||||
or
|
||||
alloc instanceof NewExpr and
|
||||
kind = "new" and
|
||||
// exclude placement new and custom overloads as they
|
||||
// may not conform to assumptions
|
||||
not alloc.(NewExpr).getAllocatorCall().getTarget().getNumberOfParameters() > 1
|
||||
or
|
||||
alloc instanceof NewArrayExpr and
|
||||
kind = "new[]" and
|
||||
// exclude placement new and custom overloads as they
|
||||
// may not conform to assumptions
|
||||
not alloc.(NewArrayExpr).getAllocatorCall().getTarget().getNumberOfParameters() > 1
|
||||
)
|
||||
}
|
||||
|
||||
@@ -40,13 +37,14 @@ predicate allocExpr(Expr alloc, string kind) {
|
||||
*/
|
||||
predicate allocExprOrIndirect(Expr alloc, string kind) {
|
||||
// direct alloc
|
||||
allocExpr(alloc, kind) or
|
||||
|
||||
allocExpr(alloc, kind)
|
||||
or
|
||||
exists(ReturnStmt rtn |
|
||||
// indirect alloc via function call
|
||||
alloc.(FunctionCall).getTarget() = rtn.getEnclosingFunction() and
|
||||
(
|
||||
allocExprOrIndirect(rtn.getExpr(), kind) or
|
||||
allocExprOrIndirect(rtn.getExpr(), kind)
|
||||
or
|
||||
exists(Expr e |
|
||||
allocExprOrIndirect(e, kind) and
|
||||
DataFlow::localFlow(DataFlow::exprNode(e), DataFlow::exprNode(rtn.getExpr()))
|
||||
@@ -59,7 +57,8 @@ predicate allocExprOrIndirect(Expr alloc, string kind) {
|
||||
* Holds if `v` is a non-local variable which is assigned with allocations of
|
||||
* type `kind`.
|
||||
*/
|
||||
private pragma[nomagic] predicate allocReachesVariable(Variable v, Expr alloc, string kind) {
|
||||
pragma[nomagic]
|
||||
private predicate allocReachesVariable(Variable v, Expr alloc, string kind) {
|
||||
exists(Expr mid |
|
||||
not v instanceof LocalScopeVariable and
|
||||
v.getAnAssignedValue() = mid and
|
||||
@@ -73,18 +72,20 @@ private pragma[nomagic] predicate allocReachesVariable(Variable v, Expr alloc, s
|
||||
* string describing the type of that allocation.
|
||||
*/
|
||||
private predicate allocReaches0(Expr e, Expr alloc, string kind) {
|
||||
(
|
||||
// alloc
|
||||
allocExprOrIndirect(alloc, kind) and
|
||||
e = alloc
|
||||
) or exists(SsaDefinition def, LocalScopeVariable v |
|
||||
// alloc
|
||||
allocExprOrIndirect(alloc, kind) and
|
||||
e = alloc
|
||||
or
|
||||
exists(SsaDefinition def, LocalScopeVariable v |
|
||||
// alloc via SSA
|
||||
allocReaches0(def.getAnUltimateDefiningValue(v), alloc, kind) and
|
||||
e = def.getAUse(v)
|
||||
) or exists(Variable v |
|
||||
)
|
||||
or
|
||||
exists(Variable v |
|
||||
// alloc via a global
|
||||
allocReachesVariable(v, alloc, kind) and
|
||||
strictcount(VariableAccess va | va.getTarget() = v) <= 50 and // avoid very expensive cases
|
||||
strictcount(VariableAccess va | va.getTarget() = v) <= 50 and // avoid very expensive cases
|
||||
e.(VariableAccess).getTarget() = v
|
||||
)
|
||||
}
|
||||
@@ -97,7 +98,7 @@ private predicate allocReaches0(Expr e, Expr alloc, string kind) {
|
||||
predicate allocReaches(Expr e, Expr alloc, string kind) {
|
||||
allocReaches0(e, alloc, kind) and
|
||||
not exists(string k2 |
|
||||
allocReaches0(e, _, k2) and
|
||||
allocReaches0(e, _, k2) and
|
||||
kind != k2
|
||||
)
|
||||
}
|
||||
@@ -108,16 +109,14 @@ predicate allocReaches(Expr e, Expr alloc, string kind) {
|
||||
* describing the type of that free or delete.
|
||||
*/
|
||||
predicate freeExpr(Expr free, Expr freed, string kind) {
|
||||
(
|
||||
freeCall(free, freed) and
|
||||
kind = "free"
|
||||
) or (
|
||||
free.(DeleteExpr).getExpr() = freed and
|
||||
kind = "delete"
|
||||
) or (
|
||||
free.(DeleteArrayExpr).getExpr() = freed and
|
||||
kind = "delete[]"
|
||||
)
|
||||
freeCall(free, freed) and
|
||||
kind = "free"
|
||||
or
|
||||
free.(DeleteExpr).getExpr() = freed and
|
||||
kind = "delete"
|
||||
or
|
||||
free.(DeleteArrayExpr).getExpr() = freed and
|
||||
kind = "delete[]"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,8 +127,8 @@ predicate freeExpr(Expr free, Expr freed, string kind) {
|
||||
*/
|
||||
predicate freeExprOrIndirect(Expr free, Expr freed, string kind) {
|
||||
// direct free
|
||||
freeExpr(free, freed, kind) or
|
||||
|
||||
freeExpr(free, freed, kind)
|
||||
or
|
||||
// indirect free via function call
|
||||
exists(Expr internalFree, Expr internalFreed, int arg |
|
||||
freeExprOrIndirect(internalFree, internalFreed, kind) and
|
||||
|
||||
@@ -7,12 +7,11 @@
|
||||
* @id cpp/new-delete-array-mismatch
|
||||
* @tags reliability
|
||||
*/
|
||||
|
||||
import NewDelete
|
||||
|
||||
from Expr alloc, Expr free, Expr freed
|
||||
where
|
||||
allocReaches(freed, alloc, "new") and
|
||||
freeExprOrIndirect(free, freed, "delete[]")
|
||||
select
|
||||
free, "This memory may have been allocated with '$@', not 'new[]'.",
|
||||
alloc, "new"
|
||||
select free, "This memory may have been allocated with '$@', not 'new[]'.", alloc, "new"
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* security
|
||||
* external/cwe/cwe-401
|
||||
*/
|
||||
|
||||
import NewDelete
|
||||
|
||||
/**
|
||||
@@ -16,22 +17,22 @@ import NewDelete
|
||||
* types of allocation and free.
|
||||
*/
|
||||
predicate correspondingKinds(string allocKind, string freeKind) {
|
||||
(
|
||||
allocKind = "malloc" and
|
||||
freeKind = "free"
|
||||
) or (
|
||||
allocKind = "new" and
|
||||
freeKind = "delete"
|
||||
)
|
||||
allocKind = "malloc" and
|
||||
freeKind = "free"
|
||||
or
|
||||
allocKind = "new" and
|
||||
freeKind = "delete"
|
||||
}
|
||||
|
||||
from
|
||||
Expr alloc, string allocKind, string allocKindSimple,
|
||||
Expr free, Expr freed, string freeKind, string freeKindSimple
|
||||
Expr alloc, string allocKind, string allocKindSimple, Expr free, Expr freed, string freeKind,
|
||||
string freeKindSimple
|
||||
where
|
||||
allocReaches(freed, alloc, allocKind) and
|
||||
freeExprOrIndirect(free, freed, freeKind) and
|
||||
allocKindSimple = allocKind.replaceAll("[]", "") and
|
||||
freeKindSimple = freeKind.replaceAll("[]", "") and
|
||||
not correspondingKinds(allocKindSimple, freeKindSimple)
|
||||
select free, "There is a " + allocKindSimple + "/" + freeKindSimple + " mismatch between this " + freeKind + " and the corresponding $@.", alloc, allocKind
|
||||
select free,
|
||||
"There is a " + allocKindSimple + "/" + freeKindSimple + " mismatch between this " + freeKind +
|
||||
" and the corresponding $@.", alloc, allocKind
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
import cpp
|
||||
|
||||
// See also InitialisationNotRun.ql and GlobalUseBeforeInit.ql
|
||||
|
||||
/**
|
||||
* Holds if `s` defines variable `v` (conservative).
|
||||
*/
|
||||
|
||||
@@ -9,39 +9,51 @@
|
||||
* external/cwe/cwe-131
|
||||
* external/cwe/cwe-120
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
class MallocCall extends FunctionCall
|
||||
{
|
||||
class MallocCall extends FunctionCall {
|
||||
MallocCall() {
|
||||
this.getTarget().hasQualifiedName("malloc") or
|
||||
this.getTarget().hasQualifiedName("std::malloc")
|
||||
this.getTarget().hasQualifiedName("malloc") or
|
||||
this.getTarget().hasQualifiedName("std::malloc")
|
||||
}
|
||||
|
||||
Expr getAllocatedSize() {
|
||||
if this.getArgument(0) instanceof VariableAccess then
|
||||
if this.getArgument(0) instanceof VariableAccess
|
||||
then
|
||||
exists(LocalScopeVariable v, ControlFlowNode def |
|
||||
definitionUsePair(v, def, this.getArgument(0)) and
|
||||
exprDefinition(v, def, result))
|
||||
else
|
||||
result = this.getArgument(0)
|
||||
exprDefinition(v, def, result)
|
||||
)
|
||||
else result = this.getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
predicate spaceProblem(FunctionCall append, string msg)
|
||||
{
|
||||
predicate terminationProblem(MallocCall malloc, string msg) {
|
||||
malloc.getAllocatedSize() instanceof StrlenCall and
|
||||
msg = "This allocation does not include space to null-terminate the string."
|
||||
}
|
||||
|
||||
predicate spaceProblem(FunctionCall append, string msg) {
|
||||
exists(MallocCall malloc, StrlenCall strlen, AddExpr add, FunctionCall insert, Variable buffer |
|
||||
add.getAChild() = strlen
|
||||
and exists(add.getAChild().getValue())
|
||||
and malloc.getAllocatedSize() = add
|
||||
and buffer.getAnAccess() = strlen.getStringExpr()
|
||||
and (insert.getTarget().hasQualifiedName("strcpy") or insert.getTarget().hasQualifiedName("strncpy"))
|
||||
and (append.getTarget().hasQualifiedName("strcat") or append.getTarget().hasQualifiedName("strncat"))
|
||||
and malloc.getASuccessor+() = insert
|
||||
and insert.getArgument(1) = buffer.getAnAccess()
|
||||
and insert.getASuccessor+() = append
|
||||
and msg = "This buffer only contains enough room for '" + buffer.getName() +
|
||||
"' (copied on line " + insert.getLocation().getStartLine().toString() + ")")
|
||||
add.getAChild() = strlen and
|
||||
exists(add.getAChild().getValue()) and
|
||||
malloc.getAllocatedSize() = add and
|
||||
buffer.getAnAccess() = strlen.getStringExpr() and
|
||||
(
|
||||
insert.getTarget().hasQualifiedName("strcpy") or
|
||||
insert.getTarget().hasQualifiedName("strncpy")
|
||||
) and
|
||||
(
|
||||
append.getTarget().hasQualifiedName("strcat") or
|
||||
append.getTarget().hasQualifiedName("strncat")
|
||||
) and
|
||||
malloc.getASuccessor+() = insert and
|
||||
insert.getArgument(1) = buffer.getAnAccess() and
|
||||
insert.getASuccessor+() = append and
|
||||
msg = "This buffer only contains enough room for '" + buffer.getName() + "' (copied on line " +
|
||||
insert.getLocation().getStartLine().toString() + ")"
|
||||
)
|
||||
}
|
||||
|
||||
from Expr problem, string msg
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
* external/cwe/cwe-119
|
||||
* external/cwe/cwe-131
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.security.TaintTracking
|
||||
|
||||
@@ -21,30 +22,34 @@ import semmle.code.cpp.security.TaintTracking
|
||||
* memcpy(dest, src, sizeof(src));
|
||||
* ```
|
||||
*/
|
||||
predicate sourceSized(FunctionCall fc, Expr src)
|
||||
{
|
||||
predicate sourceSized(FunctionCall fc, Expr src) {
|
||||
exists(string name |
|
||||
(name = "strncpy" or name = "strncat" or name = "memcpy" or name = "memmove") and
|
||||
fc.getTarget().hasQualifiedName(name))
|
||||
and
|
||||
fc.getTarget().hasQualifiedName(name)
|
||||
) and
|
||||
exists(Expr dest, Expr size, Variable v |
|
||||
fc.getArgument(0) = dest and fc.getArgument(1) = src and fc.getArgument(2) = size and
|
||||
src = v.getAnAccess() and size.getAChild+() = v.getAnAccess() and
|
||||
|
||||
fc.getArgument(0) = dest and
|
||||
fc.getArgument(1) = src and
|
||||
fc.getArgument(2) = size and
|
||||
src = v.getAnAccess() and
|
||||
size.getAChild+() = v.getAnAccess() and
|
||||
// exception: `dest` is also referenced in the size argument
|
||||
not exists(Variable other |
|
||||
dest = other.getAnAccess() and size.getAChild+() = other.getAnAccess())
|
||||
and
|
||||
|
||||
dest = other.getAnAccess() and size.getAChild+() = other.getAnAccess()
|
||||
) and
|
||||
// exception: `src` and `dest` are both arrays of the same type and size
|
||||
not exists(ArrayType srctype, ArrayType desttype |
|
||||
dest.getType().getUnderlyingType() = desttype and
|
||||
src.getType().getUnderlyingType() = srctype and
|
||||
desttype.getBaseType().getUnderlyingType() = srctype.getBaseType().getUnderlyingType() and
|
||||
desttype.getArraySize() = srctype.getArraySize()))
|
||||
desttype.getArraySize() = srctype.getArraySize()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
from FunctionCall fc, Expr vuln, Expr taintSource
|
||||
where sourceSized(fc, vuln)
|
||||
and tainted(taintSource, vuln)
|
||||
select fc, "To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size."
|
||||
where
|
||||
sourceSized(fc, vuln) and
|
||||
tainted(taintSource, vuln)
|
||||
select fc,
|
||||
"To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size."
|
||||
|
||||
@@ -11,31 +11,28 @@
|
||||
* external/cwe/cwe-119
|
||||
* external/cwe/cwe-131
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.commons.Buffer
|
||||
import LoopBounds
|
||||
|
||||
private predicate staticBufferBase(VariableAccess access, Variable v)
|
||||
{
|
||||
private predicate staticBufferBase(VariableAccess access, Variable v) {
|
||||
v.getType().(ArrayType).getBaseType() instanceof CharType and
|
||||
access = v.getAnAccess() and
|
||||
not memberMayBeVarSize(_, v)
|
||||
}
|
||||
|
||||
predicate staticBuffer(VariableAccess access, Variable v, int size)
|
||||
{
|
||||
predicate staticBuffer(VariableAccess access, Variable v, int size) {
|
||||
staticBufferBase(access, v) and
|
||||
size = getBufferSize(access, _)
|
||||
}
|
||||
|
||||
class BufferAccess extends ArrayExpr
|
||||
{
|
||||
class BufferAccess extends ArrayExpr {
|
||||
BufferAccess() {
|
||||
exists(int size |
|
||||
staticBuffer(this.getArrayBase(), _, size) and
|
||||
size != 0
|
||||
) and
|
||||
|
||||
// exclude accesses in macro implementation of `strcmp`,
|
||||
// which are carefully controlled but can look dangerous.
|
||||
not exists(Macro m |
|
||||
@@ -44,53 +41,57 @@ class BufferAccess extends ArrayExpr
|
||||
)
|
||||
}
|
||||
|
||||
int bufferSize() {
|
||||
staticBuffer(this.getArrayBase(), _, result)
|
||||
}
|
||||
int bufferSize() { staticBuffer(this.getArrayBase(), _, result) }
|
||||
|
||||
Variable buffer() {
|
||||
result.getAnAccess() = this.getArrayBase()
|
||||
}
|
||||
Variable buffer() { result.getAnAccess() = this.getArrayBase() }
|
||||
}
|
||||
|
||||
predicate overflowOffsetInLoop(BufferAccess bufaccess, string msg)
|
||||
{
|
||||
predicate overflowOffsetInLoop(BufferAccess bufaccess, string msg) {
|
||||
exists(ClassicForLoop loop |
|
||||
loop.getStmt().getAChild*() = bufaccess.getEnclosingStmt() and
|
||||
loop.limit() >= bufaccess.bufferSize() and
|
||||
loop.counter().getAnAccess() = bufaccess.getArrayOffset() and
|
||||
msg = "Potential buffer-overflow: counter '" + loop.counter().toString()
|
||||
+ "' <= " + loop.limit().toString() + " but '" + bufaccess.buffer().getName()
|
||||
+ "' has " + bufaccess.bufferSize().toString() + " elements.")
|
||||
msg = "Potential buffer-overflow: counter '" + loop.counter().toString() + "' <= " +
|
||||
loop.limit().toString() + " but '" + bufaccess.buffer().getName() + "' has " +
|
||||
bufaccess.bufferSize().toString() + " elements."
|
||||
)
|
||||
}
|
||||
|
||||
predicate bufferAndSizeFunction(Function f, int buf, int size)
|
||||
{
|
||||
(f.hasQualifiedName("read") and buf = 1 and size = 2) or
|
||||
(f.hasQualifiedName("fgets") and buf = 0 and size = 1) or
|
||||
(f.hasQualifiedName("strncpy") and buf = 0 and size = 2) or
|
||||
(f.hasQualifiedName("strncat") and buf = 0 and size = 2) or
|
||||
(f.hasQualifiedName("memcpy") and buf = 0 and size = 2) or
|
||||
(f.hasQualifiedName("memmove") and buf = 0 and size = 2) or
|
||||
(f.hasQualifiedName("snprintf") and buf = 0 and size = 1) or
|
||||
(f.hasQualifiedName("vsnprintf") and buf = 0 and size = 1)
|
||||
predicate bufferAndSizeFunction(Function f, int buf, int size) {
|
||||
f.hasQualifiedName("read") and buf = 1 and size = 2
|
||||
or
|
||||
f.hasQualifiedName("fgets") and buf = 0 and size = 1
|
||||
or
|
||||
f.hasQualifiedName("strncpy") and buf = 0 and size = 2
|
||||
or
|
||||
f.hasQualifiedName("strncat") and buf = 0 and size = 2
|
||||
or
|
||||
f.hasQualifiedName("memcpy") and buf = 0 and size = 2
|
||||
or
|
||||
f.hasQualifiedName("memmove") and buf = 0 and size = 2
|
||||
or
|
||||
f.hasQualifiedName("snprintf") and buf = 0 and size = 1
|
||||
or
|
||||
f.hasQualifiedName("vsnprintf") and buf = 0 and size = 1
|
||||
}
|
||||
|
||||
class CallWithBufferSize extends FunctionCall
|
||||
{
|
||||
class CallWithBufferSize extends FunctionCall {
|
||||
CallWithBufferSize() { bufferAndSizeFunction(this.getTarget(), _, _) }
|
||||
|
||||
Expr buffer() {
|
||||
exists(int i |
|
||||
bufferAndSizeFunction(this.getTarget(), i, _) and
|
||||
result = this.getArgument(i)
|
||||
)
|
||||
}
|
||||
|
||||
Expr statedSizeExpr() {
|
||||
exists(int i |
|
||||
bufferAndSizeFunction(this.getTarget(), _, i) and
|
||||
result = this.getArgument(i)
|
||||
)
|
||||
}
|
||||
|
||||
int statedSizeValue() {
|
||||
exists(Expr statedSizeSrc |
|
||||
DataFlow::localFlow(DataFlow::exprNode(statedSizeSrc), DataFlow::exprNode(statedSizeExpr())) and
|
||||
@@ -105,24 +106,29 @@ predicate wrongBufferSize(Expr error, string msg) {
|
||||
statedSize = min(call.statedSizeValue()) and
|
||||
statedSize > bufsize and
|
||||
error = call.statedSizeExpr() and
|
||||
msg = "Potential buffer-overflow: '" + buf.getName() +
|
||||
"' has size " + bufsize.toString() + " not " + statedSize + ".")
|
||||
msg = "Potential buffer-overflow: '" + buf.getName() + "' has size " + bufsize.toString() +
|
||||
" not " + statedSize + "."
|
||||
)
|
||||
}
|
||||
|
||||
predicate outOfBounds(BufferAccess bufaccess, string msg)
|
||||
{
|
||||
predicate outOfBounds(BufferAccess bufaccess, string msg) {
|
||||
exists(int size, int access, string buf |
|
||||
buf = bufaccess.buffer().getName() and
|
||||
bufaccess.bufferSize() = size and
|
||||
bufaccess.getArrayOffset().getValue().toInt() = access and
|
||||
( access > size or
|
||||
(access = size and not exists(AddressOfExpr addof | bufaccess = addof.getOperand()))) and
|
||||
msg = "Potential buffer-overflow: '" + buf + "' has size " + size.toString() +
|
||||
" but '" + buf + "[" + access.toString() + "]' is accessed here.")
|
||||
(
|
||||
access > size
|
||||
or
|
||||
access = size and not exists(AddressOfExpr addof | bufaccess = addof.getOperand())
|
||||
) and
|
||||
msg = "Potential buffer-overflow: '" + buf + "' has size " + size.toString() + " but '" + buf +
|
||||
"[" + access.toString() + "]' is accessed here."
|
||||
)
|
||||
}
|
||||
|
||||
from Element error, string msg
|
||||
where overflowOffsetInLoop(error, msg)
|
||||
or wrongBufferSize(error, msg)
|
||||
or outOfBounds(error, msg)
|
||||
where
|
||||
overflowOffsetInLoop(error, msg) or
|
||||
wrongBufferSize(error, msg) or
|
||||
outOfBounds(error, msg)
|
||||
select error, msg
|
||||
|
||||
@@ -8,25 +8,25 @@
|
||||
* security
|
||||
* external/cwe/cwe-562
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.pointsto.PointsTo
|
||||
|
||||
class ReturnPointsToExpr extends PointsToExpr
|
||||
{
|
||||
class ReturnPointsToExpr extends PointsToExpr {
|
||||
override predicate interesting() {
|
||||
exists(ReturnStmt ret | ret.getExpr().getFullyConverted() = this)
|
||||
and pointerValue(this)
|
||||
exists(ReturnStmt ret | ret.getExpr().getFullyConverted() = this) and
|
||||
pointerValue(this)
|
||||
}
|
||||
|
||||
ReturnStmt getReturnStmt() { result.getExpr().getFullyConverted() = this }
|
||||
}
|
||||
|
||||
from ReturnPointsToExpr ret, LocalVariable local, float confidence
|
||||
where ret.pointsTo() = local
|
||||
and ret.getReturnStmt().getEnclosingFunction() = local.getFunction()
|
||||
and not(local.isStatic())
|
||||
and confidence = ret.confidence()
|
||||
and confidence > 0.01
|
||||
where
|
||||
ret.pointsTo() = local and
|
||||
ret.getReturnStmt().getEnclosingFunction() = local.getFunction() and
|
||||
not local.isStatic() and
|
||||
confidence = ret.confidence() and
|
||||
confidence > 0.01
|
||||
select ret,
|
||||
"This may return a pointer to '" + local.getName() +
|
||||
"' (declared on line " + local.getADeclarationLocation().getStartLine().toString() +
|
||||
"), which is stack allocated."
|
||||
"This may return a pointer to '" + local.getName() + "' (declared on line " +
|
||||
local.getADeclarationLocation().getStartLine().toString() + "), which is stack allocated."
|
||||
|
||||
@@ -9,35 +9,35 @@
|
||||
* correctness
|
||||
* external/cwe/cwe-252
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
predicate unused(Expr e)
|
||||
{
|
||||
e instanceof ExprInVoidContext
|
||||
}
|
||||
predicate unused(Expr e) { e instanceof ExprInVoidContext }
|
||||
|
||||
predicate important(Function f, string message)
|
||||
{
|
||||
predicate important(Function f, string message) {
|
||||
message = "the result of this function must always be checked." and
|
||||
getOptions().alwaysCheckReturnValue(f)
|
||||
}
|
||||
|
||||
// statistically dubious ignored return values
|
||||
predicate dubious(Function f, string message)
|
||||
{
|
||||
predicate dubious(Function f, string message) {
|
||||
not important(f, _) and
|
||||
exists(Options opts, int used, int total, int percentage |
|
||||
used = count(FunctionCall fc | fc.getTarget() = f and not opts.okToIgnoreReturnValue(fc) and not unused(fc)) and
|
||||
used = count(FunctionCall fc |
|
||||
fc.getTarget() = f and not opts.okToIgnoreReturnValue(fc) and not unused(fc)
|
||||
) and
|
||||
total = count(FunctionCall fc | fc.getTarget() = f and not opts.okToIgnoreReturnValue(fc)) and
|
||||
used != total and
|
||||
percentage = used * 100 / total and
|
||||
percentage >= 90 and
|
||||
message = percentage.toString() + "% of calls to this function have their result used.")
|
||||
message = percentage.toString() + "% of calls to this function have their result used."
|
||||
)
|
||||
}
|
||||
|
||||
from FunctionCall unused, string message
|
||||
where unused(unused)
|
||||
and not exists(Options opts | opts.okToIgnoreReturnValue(unused))
|
||||
and (important(unused.getTarget(), message) or dubious(unused.getTarget(), message))
|
||||
and not unused.getTarget().getName().matches("operator%") // exclude user defined operators
|
||||
where
|
||||
unused(unused) and
|
||||
not exists(Options opts | opts.okToIgnoreReturnValue(unused)) and
|
||||
(important(unused.getTarget(), message) or dubious(unused.getTarget(), message)) and
|
||||
not unused.getTarget().getName().matches("operator%") // exclude user defined operators
|
||||
select unused, "Result of call to " + unused.getTarget().getName() + " is ignored; " + message
|
||||
|
||||
@@ -25,20 +25,14 @@ class Allocation extends FunctionCall {
|
||||
string getName() { result = this.getTarget().getQualifiedName() }
|
||||
|
||||
int getSize() {
|
||||
(
|
||||
this.getName() = "malloc" and
|
||||
this.getArgument(0).getValue().toInt() = result
|
||||
)
|
||||
this.getName() = "malloc" and
|
||||
this.getArgument(0).getValue().toInt() = result
|
||||
or
|
||||
(
|
||||
this.getName() = "realloc" and
|
||||
this.getArgument(1).getValue().toInt() = result
|
||||
)
|
||||
this.getName() = "realloc" and
|
||||
this.getArgument(1).getValue().toInt() = result
|
||||
or
|
||||
(
|
||||
this.getName() = "calloc" and
|
||||
result = this.getArgument(0).getValue().toInt() * this.getArgument(1).getValue().toInt()
|
||||
)
|
||||
this.getName() = "calloc" and
|
||||
result = this.getArgument(0).getValue().toInt() * this.getArgument(1).getValue().toInt()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,20 +25,14 @@ class Allocation extends FunctionCall {
|
||||
string getName() { result = this.getTarget().getQualifiedName() }
|
||||
|
||||
int getSize() {
|
||||
(
|
||||
this.getName() = "malloc" and
|
||||
this.getArgument(0).getValue().toInt() = result
|
||||
)
|
||||
this.getName() = "malloc" and
|
||||
this.getArgument(0).getValue().toInt() = result
|
||||
or
|
||||
(
|
||||
this.getName() = "realloc" and
|
||||
this.getArgument(1).getValue().toInt() = result
|
||||
)
|
||||
this.getName() = "realloc" and
|
||||
this.getArgument(1).getValue().toInt() = result
|
||||
or
|
||||
(
|
||||
this.getName() = "calloc" and
|
||||
result = this.getArgument(0).getValue().toInt() * this.getArgument(1).getValue().toInt()
|
||||
)
|
||||
this.getName() = "calloc" and
|
||||
result = this.getArgument(0).getValue().toInt() * this.getArgument(1).getValue().toInt()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* @tags maintainability
|
||||
* external/cwe/cwe-563
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
// Sometimes it is useful to have a class which is instantiated (on the stack)
|
||||
@@ -15,22 +16,19 @@ import cpp
|
||||
// sometimes locking is done this way.
|
||||
//
|
||||
// Obviously, such instantiations should not be treated as unused values.
|
||||
class ScopeUtilityClass extends Class
|
||||
{
|
||||
Call getAUse()
|
||||
{
|
||||
result = this.getAConstructor().getACallToThisFunction()
|
||||
}
|
||||
class ScopeUtilityClass extends Class {
|
||||
Call getAUse() { result = this.getAConstructor().getACallToThisFunction() }
|
||||
}
|
||||
|
||||
from LocalScopeVariable v, ControlFlowNode def
|
||||
where definition(v, def)
|
||||
and not definitionUsePair(v, def, _)
|
||||
and not v.isStatic()
|
||||
and not v.getAnAccess().isAddressOfAccess()
|
||||
where
|
||||
definition(v, def) and
|
||||
not definitionUsePair(v, def, _) and
|
||||
not v.isStatic() and
|
||||
not v.getAnAccess().isAddressOfAccess() and
|
||||
// parameter initializers are not in the call-graph at the moment
|
||||
and not v.(Parameter).getInitializer().getExpr() = def
|
||||
and not v.getType().getUnderlyingType() instanceof ReferenceType
|
||||
and not exists(ScopeUtilityClass util | def = util.getAUse())
|
||||
and not def.isInMacroExpansion()
|
||||
not v.(Parameter).getInitializer().getExpr() = def and
|
||||
not v.getType().getUnderlyingType() instanceof ReferenceType and
|
||||
not exists(ScopeUtilityClass util | def = util.getAUse()) and
|
||||
not def.isInMacroExpansion()
|
||||
select def, "Variable '" + v.getName() + "' is assigned a value that is never used"
|
||||
|
||||
@@ -8,17 +8,16 @@
|
||||
* security
|
||||
* external/cwe/cwe-416
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
|
||||
|
||||
/** `e` is an expression that frees the memory pointed to by `v`. */
|
||||
predicate isFreeExpr(Expr e, LocalScopeVariable v) {
|
||||
exists(VariableAccess va |
|
||||
va.getTarget() = v |
|
||||
exists(FunctionCall fc |
|
||||
fc = e |
|
||||
fc.getTarget().hasQualifiedName("free")
|
||||
and va = fc.getArgument(0)
|
||||
exists(VariableAccess va | va.getTarget() = v |
|
||||
exists(FunctionCall fc | fc = e |
|
||||
fc.getTarget().hasQualifiedName("free") and
|
||||
va = fc.getArgument(0)
|
||||
)
|
||||
or
|
||||
e.(DeleteExpr).getExpr() = va
|
||||
@@ -41,25 +40,18 @@ predicate isDerefExpr(Expr e, LocalScopeVariable v) {
|
||||
* parameter.
|
||||
*/
|
||||
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, LocalScopeVariable v) {
|
||||
v.getAnAccess() = va
|
||||
and
|
||||
va = c.getAnArgumentSubExpr(i)
|
||||
and
|
||||
not c.passesByReference(i, va)
|
||||
and
|
||||
v.getAnAccess() = va and
|
||||
va = c.getAnArgumentSubExpr(i) and
|
||||
not c.passesByReference(i, va) and
|
||||
(c.getTarget().hasEntryPoint() implies isDerefExpr(_, c.getTarget().getParameter(i)))
|
||||
}
|
||||
|
||||
class UseAfterFreeReachability extends LocalScopeVariableReachability {
|
||||
UseAfterFreeReachability() { this = "UseAfterFree" }
|
||||
|
||||
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
|
||||
isFreeExpr(node, v)
|
||||
}
|
||||
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { isFreeExpr(node, v) }
|
||||
|
||||
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
|
||||
isDerefExpr(node, v)
|
||||
}
|
||||
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { isDerefExpr(node, v) }
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
|
||||
definitionBarrier(v, node) or
|
||||
@@ -69,6 +61,5 @@ class UseAfterFreeReachability extends LocalScopeVariableReachability {
|
||||
|
||||
from UseAfterFreeReachability r, LocalScopeVariable v, Expr free, Expr e
|
||||
where r.reaches(free, v, e)
|
||||
select e,
|
||||
"Memory pointed to by '" + v.getName().toString() +
|
||||
"' may have been previously freed $@", free, "here"
|
||||
select e, "Memory pointed to by '" + v.getName().toString() + "' may have been previously freed $@",
|
||||
free, "here"
|
||||
|
||||
Reference in New Issue
Block a user